Прототипирование JavaScript: один объект-прототип или нет? - PullRequest
1 голос
/ 26 августа 2010

Я действительно не получаю прототип JavaScript.Возьмите этот код, например:

function Class(asdf) {
 if(typeof(asdf) == 'undefined') {
 } else {
  this.asdf = asdf;
 }
}
Class.prototype.asdf = "default_asdf";
Class.prototype.asdf2 = [];
Class.prototype.change_asdf = function() {
 this.asdf = "changed_asdf";
 this.asdf2.push("changed_asdf2");
}

function SubClass() {
}
SubClass.prototype = new Class("proto_class");
SubClass.prototype.constructor = SubClass;

test1 = new SubClass();
alert("test1 asdf: " + test1.asdf + " " + test1.asdf2);
test1.change_asdf();
alert("test1 asdf: " + test1.asdf + " " + test1.asdf2);
test2 = new SubClass();
alert("test2 asdf: " + test2.asdf + " " + test2.asdf2);

Первое предупреждение выдает «proto_class []», как и ожидалось.Второе оповещение выводит «change_asdf [change_asdf2]», также как и ожидалось.Но почему третье предупреждение выдает «proto_class [change_asdf2]» ?!Если исходный объект-прототип (новый класс («proto_class»)) изменяется, то почему переменная asdf не остается «change_asdf»?И если это не так, то почему массив asdf2 содержит «updated_asdf2»?Кроме того, как мне убедиться, что каждый новый экземпляр SubClass () содержит новый экземпляр Class (), как в C ++ и Java?

Ответы [ 2 ]

1 голос
/ 29 августа 2010

Это потому, что вы пишете

SubClass.prototype = new Class("proto_class");

, вы создаете прототип один экземпляр из Class.Вам нужно создать подкласс, который наследуется от прототипа его родителя.Как показывает Дэвид Фланаган в своем JavaScript: Полное руководство (§ 9.5), вы должны использовать вспомогательную функцию для создания нового объекта с указанным прототипом:

function heir(p) {
    function f(){}         // dummy constructor function
    f.prototype = p;       // specify prototype object we want
    return new f();        // create and return new object
}

(Крокфордвызывает эту функцию Object.create после так называемого свойства конструктора объекта ES5 , но, пожалуйста, не делайте этого, поскольку может вводить в заблуждение .)

В конструкторе SubClass вам необходимо вызвать конструктор класса с this, установленным на текущий объект:

function SubClass() {
    // call the parent's constructor with
    // `this` set to the current scope
    Class.call(this, "proto_class");
}

И, наконец, вы только сбросите Class.asdf2один раз, но не в функции конструктора Class или SubClass.Поэтому добавьте this.asdf2 = []; к одному из конструкторов.

Полный код теперь выглядит так:

function heir(p) {
    function f(){}         // dummy constructor function
    f.prototype = p;       // specify prototype object we want
    return new f();        // create and return new object
}

function Class(asdf) {
    if (typeof asdf != 'undefined')
        this.asdf = asdf;
}

Class.prototype.asdf = "default_asdf";
Class.prototype.asdf2 = [];
Class.prototype.change_asdf = function() {
    this.asdf = "changed_asdf";
    this.asdf2.push("changed_asdf2");
}

function SubClass() {
    // call the parent's constructor with
    // `this` set to the current scope
    Class.call(this, "proto_class");
    this.asdf2 = [];
}

SubClass.prototype = heir(Class.prototype);
SubClass.prototype.constructor = SubClass;

test1 = new SubClass();
alert("test1 asdf: " + test1.asdf + " " + test1.asdf2);
test1.change_asdf();
alert("test1 asdf: " + test1.asdf + " " + test1.asdf2);
test2 = new SubClass();
alert("test2 asdf: " + test2.asdf + " " + test2.asdf2);
0 голосов
/ 20 октября 2010

Это потому, что asdf2 является изменяемым массивом в Class.prototype. Этот массив используется всеми экземплярами, которые делегируют этот прототип. Если вы хотите, чтобы у каждого экземпляра был отдельный asdf2, вы должны присвоить его this.asdf2 некоторым способом.

Обратите внимание, что вы присваиваете this.asdf, но никогда не присваиваете this.asdf2, вы просто нажимаете на существующий массив.

var house = {nice: true};
var me = {home: house};
var roomie = {home: house};

// Now roomie has a party and trashes the place.
roomie.home.nice = false;

//and how's my house?
me.home.nice === false;
// because house is shared.

Разделение house в этом примере аналогично разделению asdf2 в вопросе.

...