Object.create Цепочки прототипов

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

Вчера я прочитал о 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 не ломается в этом коде (мне кажется, что он работает только для функций)

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

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

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

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

Спасибо за все старания =)

Отвечать

Хорошо, когда я это сделаю

Ничего = {}

base.prototype = Ничего;

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

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

base.prototype.constructor = база;

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

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

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

Верхний экземпляр базы // ложь

Обновлять

В итоге я сделал это так:

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 сделает все как положено, возможно, какой-то строгий режим (??)


person Moritz Roessler    schedule 28.06.2012    source источник


Ответы (1)


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

да.

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

да. Точнее, прототип Human1, Human, имеет свойство "ходить", указывающее на него.

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

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

  • Цепочка прототипов экземпляров Human включает base. Это странно, и вам нужно перезаписать методы создания и расширения для каждого экземпляра. Обычный метод заключается в том, что «классы» содержат свойство «прототип», от которого наследуются их экземпляры.
  • Ваш шаблон нарушает оператор 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;
};

To the extended question:

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

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

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

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

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 (обычный метод for-in-copy).

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

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

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

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

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

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

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

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

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

person Bergi    schedule 28.06.2012
comment
Вы не можете форматировать код в комментариях. Вы должны удалить их и добавить код к своему вопросу, отредактировав его. - person Bergi; 28.06.2012
comment
Оператор instanceof работает только для объектов Function. Попробуйте Human1 instanceof Human с исходным кодом. - person Bergi; 28.06.2012
comment
Thnx =) Отредактировал ответ, да, в исходном коде он не работает =) В любом случае я не понимаю, почему он должен работать на чем-либо, кроме конструктора, мне кажется, это неправильно - person Moritz Roessler; 28.06.2012
comment
Хорошо, я ответил на первую часть. Надеюсь ответить на все остальные вопросы позже. - person Bergi; 28.06.2012
comment
Большое спасибо =) Я ценю это, это действительно помогает мне немного лучше понять javascript =) о да, верно, это была ошибка, которую я хотел сделать base.prototype.constuctor, со мной часто случается, и в большинстве случаев я не осознайте это перед запуском, не имеет никакого смысла, устанавливая конструктор для самого конструктора (?) - person Moritz Roessler; 28.06.2012
comment
(правильно ли я понял, что сама функция находится в свойстве конструктора прототипа функций?) - person Moritz Roessler; 28.06.2012
comment
Вау . большое спасибо =) Действительно хороший и понятный ответ, я даже понял этот код при первом прочтении, спасибо за ваши комментарии, и не только это, я довольно долго искал что-то вроде Object.extend(), это потрясающе =) Я читал эти две ссылки раньше, но это не сделало эти вещи для Object.create ясными в моей голове =) Еще раз спасибо, я никогда не ожидал такого полезного ответа, я действительно ценю усилия, которые вы вложили в объяснение всего этого =) Так изучение javascript становится еще более приятным; - person Moritz Roessler; 28.06.2012
comment
Object.extend не является нативной функцией, но вы найдете ее версию в каждой общей библиотеке... - person Bergi; 28.06.2012
comment
о, хорошо =), но я мог бы установить Object.prototype.extend = function () {...}, используя циклы for in, как вы упомянули =) // применимо ли это к любому типу объекта, поскольку все в javascript является объектом (это ?) ? - person Moritz Roessler; 28.06.2012
comment
Да, и это проблема. Каковы подводные камни расширения Object.prototype? - person Bergi; 28.06.2012