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

发布于 2024-10-04 01:56:16 字数 797 浏览 9 评论 0原文

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。

无法在事物实例上设置 thing1.aa ,因为它会抛出“无法在未定义时设置”错误。 此时它沿着原型链向上查找已定义的 Entity.a 并将 Entity.aa 设置为新值。

[进一步编辑]

正如 @IvoWetzel 所说,设置 thing1.b 不会触及原型链,因为设置属性不会。设置 thing1.aa 需要执行两个步骤。 thing1.a 上的 getter 触及原型链,后跟 .a 的 setter

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

I'm having difficulty with setting prototypical inheritance in javascript. Ideally I want both thing1 and thing2 to have their own clean copy of the "new Entity prototype".

using this.__proto__ is something I want to avoid

[Edit]

I have a rough idea of how this working.

Setting thing1.b sets the b property on the Thing instance. which does not touch the Entity.b defined in the prototype chain.

Where as setting thing1.a.a on the Thing instance cannot been done because it would throw an "cannot set a on undefined" error. That's when it goes up the prototype chain to find Entity.a which is defined and sets Entity.a.a to a new value.

[Further Edit]

As @IvoWetzel says setting thing1.b does not touch the prototype chain because setting properties does not. Where as setting thing1.a.a does two steps. A getter on thing1.a which touches the prototype chain followed by a setter of .a

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你的背包 2024-10-11 01:56:16

您可以做的一件事是在 Thing应用Entity构造函数的逻辑,例如:

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

A thing you could do is to apply the logic of your Entity constructor inside Thing, for example:

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
白日梦 2024-10-11 01:56:16

虽然 CMS 已发布解决方案,但为什么 thing2.b 返回 5 以及为什么 thing2.aa 解析为对象?

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 沿着原型链向上查找属性。但是,当您设置属性时,它不会沿着链向上移动。

While CMS has posted a solution, why does thing2.b return 5 and why does thing2.a.a resolve to the object?

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
              }
      }

All the trouble is about JavaScript going up the prototype chain in order to find properties. But when you set properties it does not go up the chain.

⊕婉儿 2024-10-11 01:56:16

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

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

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

That's because JavaScript objects are always treated as references.

Therefore when you change the this.a object by doing a.a.a = 3; you're changing that one object in memory. New instances of Thing will reference that same object in memory because the Entity constructor is not called every time Thing is, and the this.a object remains the same.

I would put this.a outside the prototype chain, probably directly inside the Thing constructor. This would make it so that a new version of this.a is created in memory every time Thing is instantiated.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文