Как использовать цепочечное наследование прототипа javascript? - PullRequest
3 голосов
/ 24 ноября 2010
function Entity() {
    this.a = {a: 4};
    this.b = 5;
}

function Thing() {}
Thing.prototype = new Entity;

var thing1 = new Thing;
thing1.a.a = 3;
thing1.b = 4;
var thing2 = new Thing;
console.log(thing2.a.a); // prints 3 instead of 4. I would like 4.
console.log(thing2.b) // prints 5 as wanted

У меня проблемы с настройкой прототипического наследования в javascript.В идеале я хочу, чтобы и thing1, и thing2 имели свою собственную чистую копию "нового прототипа сущности".

с использованием this.__proto__ - это то, чего я хочу избежать

[Edit]

У меня есть приблизительное представление о том, как это работает.

Настройка thing1.b устанавливает свойство b в экземпляре Thing.который не касается Entity.b, определенного в цепочке прототипов.

Где, как установка thing1.aa для экземпляра Thing, не может быть выполнена, потому что он выдаст ошибку «не могу установить неопределенное». Это , когда он идет вверх по цепочке прототипов, чтобы найти Entity.a, который определен и устанавливает Entity.aa в новое значение.

[Дальнейшее редактирование]

As @IvoWetzel говорит, что настройка thing1.b не затрагивает цепочку прототипов, потому что настройка свойств этого не делает.Где, как установка thing1.aa делает два шага. getter на thing1.a, который касается цепочки прототипов, за которым следует установщик .a

Ответы [ 3 ]

6 голосов
/ 24 ноября 2010

Что вы можете сделать, это применить логику вашего Entity конструктора внутри Thing, например:

function Entity() {
    this.a = {a: 4};
    this.b = 5;
}
Entity.prototype.c = 6;

function Thing() {
  Entity.apply(this, arguments); // ejecutes the assignments made in Entity
}
Thing.prototype = new Entity;

var a = new Thing;
a.a.a = 3;

var b = new Thing;
console.log(a.a.a); // 3
console.log(b.a.a); // 4

console.log(a.b);   // 5
console.log(b.b);   // 5

console.log(a.c);   // 6
console.log(b.c);   // 6
2 голосов
/ 24 ноября 2010

Пока CMS опубликовала решение, почему thing2.b возвращает 5 и почему thing2.a.a разрешает объект?

var thing1 = new Thing;

// thing1 has no a, but the prototype has so a.a is essentially the a of Entity
thing1.a.a = 3;

// Sets b on thing1, setting does not go up the prototype chain(!)
thing1.b = 4;  

// that's what thing1 looks like
Thing {proto: Entity { 
                      a: { <--- gets resolved 
                          a: 3 <-- gets set
                      }, 
                      b: 5
              },
              b: 4 <-- gets set directly
      }


var thing2 = new Thing;

// thing2.a does not exist, so we look up the prototype and find a on Entity
console.log(thing2.a.a); 

// thing2.b also does not exists, so once again we look up the prototype to find b on Entity
console.log(thing2.b);

// that's what thing2 looks like
Thing {proto: Entity {
                      a: {
                          a: 3 <- gets resolved
                      },
                      b: 5 <- gets resolved
              }
      }

Вся проблема в том, что JavaScript идет вверх по цепочке прототипов в порядкенайти свойства.Но когда вы устанавливаете свойства, не идет вверх по цепочке.

0 голосов
/ 24 ноября 2010

Это потому, что объекты JavaScript всегда обрабатываются как ссылки.

Поэтому, когда вы изменяете объект this.a, делая a.a.a = 3;, вы изменяете этот один объект в памяти.Новые экземпляры Thing будут ссылаться на тот же объект в памяти, потому что конструктор Entity вызывается не каждый раз, когда Thing, а объект this.a остается неизменным.

Я бы поставил this.a вне цепочки прототипов, возможно, непосредственно внутри конструктора Thing.Это позволит создать новую версию this.a в памяти каждый раз, когда создается экземпляр Thing.

...