объектный литерал, используемый в унаследованном свойстве, изменяет все экземпляры класса - PullRequest
4 голосов
/ 29 марта 2012

У меня есть следующий код (ObjA), и он работает, как и следовало ожидать, экземпляр 'a1' имеет те же свойства, что и 'a2', но с другими значениями.a2:
http://www.flickr.com/photos/76617756@N02/6879283032/

Далее у меня есть следующий ObjB, который наследуется от ObjA.Экземпляры 'b1' и 'b2' имеют одинаковые свойства и разные значения для свойств propA и propB, но по какой-то причине objLiteral одинаков в обоих, как если бы он ссылался на один и тот же объект.информация для b1 и b2:
http://www.flickr.com/photos/76617756@N02/6879283088/

Может кто-нибудь помочь мне понять, что происходит?Что я должен сделать, чтобы получить то, что я ожидаю?Ваша помощь очень ценится.

1 Ответ

3 голосов
/ 29 марта 2012

Ну, оба объекта b1 и b2 имеют одинаковый прототип, а именно экземпляр ObjA:

ObjB.prototype = new ObjA();

, следовательно, они наследуют и имеют доступ к его свойствам.,b1.objLiteral и b2.objLiteral относятся к одному и тому же объекту:

enter image description here

и

> b1.objLiteral === b2.objLiteral
  true

Чтобы исправить это, необходимо создатьновый объект каждого экземпляра.Обычно это делается путем вызова «родительского» конструктора внутри «дочернего» конструктора:

function ObjB() {
    ObjA.call(this);
    this.propB = 2;
}

ObjA.call(this) вызовет ObjA, а внутри этой функции this будет ссылаться на аргумент, переданный вcall [MDN] , в данном случае новый экземпляр ObjB:

enter image description here

Как вы можете видеть, objLiteral теперь является свойством каждого экземпляра:

> b1.objLiteral === b2.objLiteral
  false

Во-первых, чтобы избежать этой путаницы, установите экземпляр родительского конструктора в качестве прототипа дочернего элемента.конструктор следует избегать.Что если родительский конструктор ожидает аргументы, специфичные для экземпляра?Что бы вы передали ObjA в этом случае?

Лучше установить прототип дочернего конструктора равным прототипу родительского конструктора (с одним уровнем косвенности) и вызватьродительский конструктор, как указано выше:

function inherit(Child, Parent) {
    var Tmp = function() {};
    Tmp.prototype = Parent.prototype;
    Child.prototype = new Tmp();
    Child.prototype.constructor = Child;
}

inherit(ObjB, ObjA);

Tmp, чтобы предотвратить расширение Parent.prototype, если вы расширите Child.prototype позже.


Относительно propA:

Это «работает», потому что вы присваиваете ему новое значение.

Здесь снова объекты, после присвоения свойств x.objLiteral и x.propA.Вы можете видеть, что объекты не имеют собственного свойства objLiteral, но имеют собственное propA:

enter image description here

Если вместо этого вы назначите новое значение *От 1073 * до objLiteral, например, через

b1.objLiteral = {hello: 42};

b1 теперь будет иметь свое собственное свойство objLiteral, которое затеняет наследуемое:

enter image description here

...