Object.create Prototype Chains

Начальный вопрос

Вчера я читал об объекте ECMAScript 5 Object.create(). И я хотел начать создавать цепочки прототипов в моем коде с помощью этого метода вместо установки прототипа и его конструктора, мне нравится, что вы можете напрямую устанавливать доступный для записи конфигурируемый и т. Д.

Я попробовал это так

function printobject(msg, obj) {
    if (msg) {
        document.write("<b>" + msg + "</b><br>");
        document.write("<hr><br>");
    }
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            if (obj[prop].toString() !== "[object Object]") {
                document.write(prop + " : " + obj[prop] + "<br>");
            }
            else {
                document.write("<b>" + prop + " : " + obj[prop] + "</b><br>");
                printobject("", obj[prop]);
            }
        }
    }
    if (msg) {
        document.write("<br><hr><br>");
    }
};
var base = {
    extend: function () { //extend this Object
        var args = Array.prototype.slice.call(arguments);
        printobject("Arguments to Extend", args)
        var that = Object.create(this, (args ? args.shift() : {}));
        var arg = args.shift() || {};
        printobject("Copy Properties to New Object", arg);
        for (var prop in arg) {
            that[prop] = arg[prop];
        }
        // Object.freeze(that);       
        return that;
    },
    create: function () { //Creates new instances of the Object
        var that = Object.create(this, {
            extend: {
                value: null,
                writable: false,
                configurable: false
            }, //sets extend and create to null so you cant create a new instance when used create ( use extend instead);
            create: {
                value: null,
                writable: false,
                configurable: false
            }
        });
        that.init.apply(that, arguments); //call init function for the new created object; 
        return that;
    },
    init: function () {
        printobject("No Initfunction supplied for New Object", this);
    } // Empty init function for fallback
}
var Human = base.extend({
    name: {
        value: "test"
    }
}, {
    init: function (name) {
        alert(name + " has been created");
        this.name = name;
    },
    walk: function () {
        alert(this.name + " walks");
    }
});
var Human1 = Human.create("test2");
//alert("Human1 - Name:" + Human1.name);
Human1.walk();
Human.walk = function () {
    alert("Walk has been overwritten")
}; //Object freezed 
Human1.walk();
Human1.create = function () {
    alert("Overwrite create");
}; //Doesnt exist in created     Object
Human1.create(); ?
  • У методов, приведенных в Human существует только один раз в баран? а также Human1.walk() указывает на это?
  • Интересно, это правильный подход? Я относительно новичок в JavaScript.

Это код на jsfiddle.

Ответ

Во-первых, большое спасибо, что делает вещи более понятными =) Но, 1: когда я делаю это таким образом, экземпляры наследуют от прототипа своего конструктора (?)

 Nothing = {};
function base() {
this.inherit = function(constructor) {
    alert("inherit");
    var obj = constructor;
    obj.constructor = constructor;
    obj.prototype = this;
   return obj ;  
 }
 ;}
base.prototype = Nothing;
base.constructor = base;
var Top = new base();       
var Human = Top.inherit(function(name) {
        this.name = name;
});
var Paul = new Human("Paul");
alert(Paul.name);
alert(Paul instanceof Human); //true `

2: Таким образом, оператор instanceof не нарушается в этом коде (то, что он работает для функций, только кажется мне понятным)

Но, написанный таким образом, Пол все еще наследует метод attribute () от прототипа Top, и мне нужно его перезаписать. Но если я не хочу, чтобы экземпляр Human наследовал метод, как мне это сделать?

И я не могу установить дескрипторы свойств, как wrtable, кроме как с помощью Objkect.defineproperty (?)

Итак, каковы основные преимущества использования Object.create () для наследования от Objects против установки прототипов и конструкторов? знак равно

3: О, да, да, это верно, это не расширение базового объекта =) Спасибо за предложение =)

Спасибо за все усилия =)

Ответ

Хорошо, когда я

Ничего = {}

base.prototype = Nothing;

это не мешает так идти по цепочке прототипов до Object.prototype? если нет, есть ли способ сделать это? =) Будет ( Object.create(null);) сделать это,

и я думал, что должен был установить

base.prototype.constructor = base;

потому что иначе конструктор прототипов

var Top = новая база ();

будет Nothings или не будет наследовать конструктор где-нибудь вверх по цепочке прототипов, если для прототипа задано Nothing ->

Top instanceof base // false

Обновить

Я закончил тем, что делал это теперь так:

var base = {
// a tiny little selfmade prototypical inheritance system
// you are free to add function arguments for extending the created objects
// neither instanceof nor .constructor is featured, because "classes" are no functions
    create: function(extension,desc) {
        // instances inherit from the proto objects
        var newInst = Object.create(this.proto, desc);
        if(this.proto.childExtendable) //if Subclass allows its Children to be Extendible, do so
            newInst.extend(extension);
        if(newInst.init||this.proto.init) //4
            newInst.init()                          
        return newInst
    },
    inherit: function(props) {
        // the "class" inherits static methods from the class
        var sub = Object.create(this);
        // and the proto objects inherits from the parent proto
        sub.proto = Object.create(this.proto);
        props.protect = this.protect;
        if(props.childExtendable)
            props.extend = this.extend;
        this.extend.call(sub.proto, props);
        return sub;
    }, 
    extend: function (props) {
        for (var prop in props) {
            var propmatch = prop.match(/(.*?)__(.{1,5}?)__(.*)/)||["",prop,"",""];
            this[propmatch[1]+propmatch[3]] = props[prop];
            if(propmatch[2])
                this.protect(propmatch[1]+propmatch[3],propmatch[2]);           
        }
    },
    protect: function(prop,flags) { //with each call it toggles the given flags,  so you can protect funcitons given to the inherit function ;; //This should be available to all childs, but adding it to the base.proto, it changes Object.prototyppe ( therefore not a good idea)
        var d  = Object.getOwnPropertyDescriptor(this, prop);
        if (flags.match(/w/)){
             Ti.API.info("Setting writable for propertie " + prop + " in Object " + this + " to " + !d.writable);
             Object.defineProperty(this, prop, {writable:!d.writable});};
        if (flags.match(/c/)){
            Ti.API.info("Setting configurable for propertie " + prop + "in Object " + this);
            Object.defineProperty(this, prop, {configurable:!d.configurable});};
        if (flags.match(/e/)){
            Ti.API.info("Setting enumerable for propertie " + prop + "in Object " + this);
            Object.defineProperty(this, prop, {configurable:!d.enumerable});};
        if (flags.match(/a/)){
            Ti.API.info("Setting enumerable for propertie " + prop + "in Object " + this);
            Object.preventExtensions(this);};
   },
    init: function() {},
    proto: Object.prototype // or null, if you want
};

var Human = base.inherit({ //will be put in Human.proto
    childExtendable:true,
    init:function() {alert("Humans Init for all Instances")},
    say:function() { alert("Hi, I'm "+this.name); }
});
Human.proto.name = "default"; // You could use an argument to the inherit function
                              // I just want to make clear what happens
Ti.API.info(Object.getPrototypeOf(Function) + "a");
var paul = Human.create({ //extends this object
    name: "Paul",
    test: function() {alert("test")},
    init__wce__: function() {alert("Pauls Own Init")},
    say__w__ : function() { alert("Hi, I'm" + this.name + "s Own Function")}
});
paul.name = "Paul";           // and again, the create function might do it for you
paul.say = function() {alert("Pauls say is overwritten")} // define init without __wce__ and it will be overwritten
paul.say(); // -> "Hi, I'm Paul"

Просто если кому-то все равно
Тем не менее, jsfiddle не будет запускать это, Titanium делает все как положено, может быть, какой-то строгий режим (??)

1 ответ

Решение

Существуют ли методы, данные в Человеке, только один раз в баране?

Да.

и Human1.walk() указывает на это?

Да. Чтобы быть более правильным, прототип Human1, Human, имеет свойство "прогулка", указывающее на него.

Интересно, это правильный подход? Я относительно новичок в JavaScript.

Я бы сказал нет, потому что это слишком сложно и отчасти неправильно.

  • Прототип цепочки экземпляров человека включает base, Это странно, и вам нужно перезаписать методы create и extension для каждого экземпляра. Обычный метод состоит в том, что "классы" содержат свойство "prototype", от которого наследуются их экземпляры.
  • Ваш образец ломает instanceof оператор, хотя это может быть незначительной проблемой.
  • Метод расширения сбивает с толку. Он не расширяет сам объект, но создает новый объект, унаследованный от него, и устанавливает для него свойства и дескрипторы свойств. Лучшая реализация того же самого:

base.inherit = function(descs, props) {
    // creates a new object inheriting from this
    var that = Object.create(this, descs); // will even work when undefined
    if (props)
        for (var prop in props)
            that[prop] = props[prop];
    // Object.freeze(that);       
    return that;
};

На расширенный вопрос:

base.prototype = Nothing​;
base.constructor = base;

совершенно бесполезно. Во-первых, свойство "prototype" любой функции является (почти) пустым объектом по умолчанию, пока вы его не перезапишите. Нет необходимости устанавливать его nothing:-)

А свойство "конструктор" обычно является свойством прототипа. Он будет наследоваться всеми экземплярами, указывающими на функцию-конструктор. Вам нужно только установить его явно при перезаписи свойства "prototype" функции - и вы не должны устанавливать свойство "constructor" для самой функции.

(продолжение:) Я хотел бы больше узнать о таком решении:

var base = {
// a tiny little selfmade prototypical inheritance system
// you are free to add function arguments for extending the created objects
// neither instanceof nor .constructor is featured, because "classes" are no functions
    create: function([desc]) {
        // instances inherit from the proto objects
        return Object.create(this.proto, [desc]);
    },
    inherit: function([props]) {
        // the "class" inherits static methods from the class
        var sub = Object.create(this);
        // and the proto objects inherits from the parent proto
        sub.proto = Object.create(this.proto);
        [Object.extend(sub.proto, props);]
        return sub;
    },
    proto: Object.prototype // or null, if you want
};

var Human = base.inherit();
Human.proto.name = "default"; // You could use an argument to the inherit function
                              // I just want to make clear what happens
Human.proto.say = function() { alert("Hi, I'm "+this.name); };

var paul = Human.create();
paul.name = "Paul";           // and again, the create function might do it for you
paul.say(); // -> "Hi, I'm Paul"

Сюда, paul наследуется от Human.proto наследуется от base.proto который Object.prototype или же null, А также Human наследуется от baseт.е. вы могли бы легко построить "подкласс" с Human.inherit(),

Хотите ли вы использовать дескрипторы свойств или нет, это ваш выбор. Везде, где вы что-то создаете и расширяете, вы можете использовать Object.defineProperties (или второй аргумент Object.create) так же как Object.extend (обычный метод для копирования).

Каковы основные преимущества использования Object.create() для наследования от Objects против установки прототипов и конструкторов?

Это выбор дизайна. Object.create не будет вызывать функцию [constructor] для встроенного объекта. См. Использование "Object.create" вместо "new" или Понимание разницы между Object.create() и новым SomeFunction() для получения дополнительной информации.

base.prototype = {}; не мешает ли так идти по цепочке прототипов до Object.prototype?

Да. Пустой объект (созданный вашим литералом) все еще имеет Object.prototype в своей цепочке. Единственный способ сделать это Object.create(null) (не шим с new).

я думал, что должен был установить base.prototype.constructor = base;

Не в этом дело. Иметь function base(){...}устанавливая его свойство "prototype" в {constructor: base} абсолютно ничего не меняет (за исключением того, что "конструктор" в перечисляемом сейчас) - каждая функция имеет такой объект по умолчанию, включая "конструктор".

Таким образом, только когда вам нужно перезаписать свойство "prototype" новым объектом, как это происходит, когда вы позволяете ему наследовать от прототипа другой функции, вы можете добавить это вспомогательное свойство: MySubClass.prototype = Object.create(MyClass.prototype, {constructor:{value:MySubClass}});

иначе...

Ничего бы не случилось Свойство "конструктор" на объектах-прототипах не требуется для языковых функций (например, instanceof), и редко используется. Вполне вероятно, что ничего не ломается.

Другие вопросы по тегам