我如何使用链式javascript原型继承?

时间:2010-11-24 00:03:37

标签: javascript prototype scope this prototyping

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__是我想要避免的事情

[编辑]

我大致了解这是如何运作的。

设置thing1.b在Thing实例上设置b属性。它不接触原型链中定义的Entity.b.

因为它会抛出“无法设置未定义的”错误,因此无法在Thing实例上设置thing1.a.a。 那是当它上传原型链以找到已定义的Entity.a并将Entity.a.a设置为新值。

[进一步编辑]

正如@IvoWetzel所说设置thing1.b不会触及原型链,因为设置属性不会。设置thing1.a.a的地方有两个步骤。在thing1.a上的 getter 触及原型链,后跟一个.a

的setter

3 个答案:

答案 0 :(得分:6)

您可以做的事情是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

答案 1 :(得分:2)

虽然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在原型链中上升以便找到属性。但是当你设置属性时,不会上去。

答案 2 :(得分:0)

这是因为JavaScript对象总是被视为引用。

因此,当您通过执行this.a更改a.a.a = 3;对象时,您将更改内存中的一个对象。 Thing的新实例将在内存中引用相同的对象,因为每次Entity都不会调用Thing构造函数,并且this.a对象保持不变。

我会将this.a放在原型链之外,可能直接放在Thing构造函数中。这样就可以在每次this.a实例化时在内存中创建新版本的Thing