代码之家  ›  专栏  ›  技术社区  ›  Raynos

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

  •  3
  • Raynos  · 技术社区  · 14 年前
    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设置对象实例的b属性。它不触及原型链中定义的实体b。

    其中,在Thing实例上设置thing1.a.a无法完成,因为它将抛出“cannot set a on undefined”错误。 那是 当它在原型链上查找实体时,定义实体并将实体a.a设置为新值。

    [进一步编辑]

    正如@IvoWetzel所说,设置thing1.b不会触及原型链,因为设置属性不会。在这里设置1.a.a做两个步骤。一个 吸气剂 关于1.a,它接触到原型链,然后是.a的setter

    3 回复  |  直到 14 年前
        1
  •  6
  •   Christian C. Salvadó    14 年前

    你能做的就是 应用 你的逻辑 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
  •  2
  •   Ivo Wetzel    14 年前

    虽然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为了找到属性而在原型链上运行。但是当你设置属性时 没有 上链子。

        3
  •  0
  •   Luca Matteis    14 年前

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

    因此当你改变 this.a 通过做来反对 a.a.a = 3; 你在改变记忆中的一个对象。的新实例 Thing 将引用内存中的同一对象,因为 Entity 构造函数不是每次都调用 事情 是,而且 这个。a 对象保持不变。

    我会把 这个。a 在原型链之外,可能直接在 事情 构造函数。这将使它成为 这个。a 每次都在内存中创建 事情 已实例化。