javascript - 原型链
javascript - prototype chain
请考虑这样的代码:
class a {
constructor() {
this.test = "test from a";
this.testA = "X";
}
mimi() {
console.log('aaaaaaaa', this.test, this.testA)
}
}
class b extends a {
constructor() {
super();
this.test = "test from b"
}
mimi() {
console.log('bbbbbbbb', this.test, this.testA)
}
}
class c extends b {
constructor() {
super();
this.test = "test from c"
}
mimi() {
console.log('cccccccc', this.test, this.testA)
}
meme() {
var test = kalreg.__proto__.__proto__;
test.mimi();
var test2 = kalreg.__proto__.__proto__.__proto__;
test2.mimi();
}
}
var kalreg = new c(); kalreg.mimi(); kalreg.meme();
我得到的输出是:
cccccccc test from c X
bbbbbbbb undefined undefined
aaaaaaaa undefined undefined
我的对象逻辑让我使用“a”作为最通用的class,“b”是一个它的子项,而“c”是“b”的子项。我希望“c”具有“b”和"a"的所有方法和属性,但“[=32]的部分功能=]a”被“b”覆盖,所以“c”访问被覆盖功能的唯一方法是使用原型链。
不幸的是,我的方法行不通,所以问题是:
- 在
meme()
函数中,如何避免 kalreg.proto - 有人告诉我这种访问原型的方式对代码来说很糟糕而且很危险。
在我看来,输出中不应该有"undefined",但是,有。
预期输出为:
来自 c X 的 cccccccc 测试
bbbbbbbb 测试来自 b X
aaaaaaaa 来自 X
的测试
如何实现?
谢谢!
in meme() function
, how to avoid kalreg.proto
在确实需要从超类访问 属性 的用例中使用 super
(但请注意,这对 test
和 [=14 没有帮助=],因为它们不在超类或其 prototype
对象上,它们在使用 new c
创建的实例上;更多内容见下文)。
另外:避免__proto__
。在需要访问对象原型的极少数情况下,请使用 Object.getPrototypeOf
.
in my opinion there should be no "undefined" in output however there is. expected output is:
cccccccc test from c X
bbbbbbbb test from b X
aaaaaaaa test from a X
输出是正确的,因为您调用 mimi
的原型对象没有 test
或 testA
属性。只有使用 new c
创建的对象才具有这些属性。而且只有一个这样的对象,所以 test
将是 "test from c"
无论你调用哪个 mimi
,而 testA
将永远是 "X"
.
在评论中,您问过当每个构造函数中都有 this.test = ...
时,怎么可能只有一个 test
。完成后让我们看看内存中的内容 var kalreg = new c();
:
+−−−−−−−−−−−−+
a−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−>| (function) | +−−−>(Function.prototype)
| +−−−−−−−−−−−−+ |
| | __proto__ |−−+ +−−−−−−−−−−−−−+
| | prototype |−−−−−−−−−−+−>| (object) |
| +−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+
| | | __proto__ |−−>...
+−−−−−−−−−−−−+ | | | constructor |−−>a
b−−−−−−−−−−−−−−−−−−−+−>| (function) | | | | mimi |−−>...
| +−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−+
| | __proto__ |−+ +−−−−−−−−−−−−−+ |
| | prototype |−−−−−−−−+−>| (object) | |
| +−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+ |
| | | __proto__ |−−+
+−−−−−−−−−−−−+ | | | constructor |−−>b
c−−−>| (function) | | | | mimi |−−>...
+−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−+
| __proto__ |−+ +−−−−−−−−−−−−−+ |
| prototype |−−−−−−−+−>| (object) | |
+−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+ |
| | __proto__ |−+
| | constructor |−−>c
+−−−−−−−−−−−−+ | | mimi |−−>...
kalreg−−−>| (object) | | | meme |−−>...
+−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+
| __proto__ |−−+
| test |
| testA |
+−−−−−−−−−−−−+
如你所见,只有kalreg
指向的对象有test
或testA
。为什么?因为在调用每个构造函数期间,this
指的是那个对象;这就是 new
和 super()
的工作原理。因此,由于 this
引用该对象,每个构造函数都执行其 this.test = ...
行,并且由于 c
中的那个是 运行 的最后一个,它“获胜”。 =57=]
您可以访问 mimi
方法的超类版本,但由于它们都显示 test
属性,因此它们都会显示 "test from c"
。要显示不同的内容,它们必须显示 不同的 属性。此外,使用 super
你只能向上一级,所以如果你想向上两级,你要么使用 a.prototype.mimi
(或明确地使用 this.__proto__.__proto__.mimi
,要么在b
调用 a
的 mimi
.
每个级别具有不同属性的示例,并且 b
提供 superMimi
因此 c
可以使用 a
的 mimi
:
class a {
constructor() {
this.testA = "test from a (this.testA)";
}
mimi() {
console.log('aaaaaaaa', this.testA);
}
}
class b extends a {
constructor() {
super();
this.testB = "test from b (this.testB)";
}
mimi() {
console.log('bbbbbbbb', this.testB)
}
superMimi() {
return super.mimi();
}
}
class c extends b {
constructor() {
super();
this.testC = "test from c (this.testC)";
}
mimi() {
console.log('cccccccc', this.testC);
}
meme() {
super.mimi(); // Uses b's version
super.superMimi(); // Uses a's version
this.__proto__.__proto__.__proto__.mimi.call(this); // Also uses a's version
var p = Object.getPrototypeOf(this);
var p2 = Object.getPrototypeOf(p);
var p3 = Object.getPrototypeOf(p2);
p3.mimi.call(this); // Also uses a's version
}
}
var kalreg = new c();
kalreg.mimi();
kalreg.meme();
请考虑这样的代码:
class a {
constructor() {
this.test = "test from a";
this.testA = "X";
}
mimi() {
console.log('aaaaaaaa', this.test, this.testA)
}
}
class b extends a {
constructor() {
super();
this.test = "test from b"
}
mimi() {
console.log('bbbbbbbb', this.test, this.testA)
}
}
class c extends b {
constructor() {
super();
this.test = "test from c"
}
mimi() {
console.log('cccccccc', this.test, this.testA)
}
meme() {
var test = kalreg.__proto__.__proto__;
test.mimi();
var test2 = kalreg.__proto__.__proto__.__proto__;
test2.mimi();
}
}
var kalreg = new c(); kalreg.mimi(); kalreg.meme();
我得到的输出是:
cccccccc test from c X
bbbbbbbb undefined undefined
aaaaaaaa undefined undefined
我的对象逻辑让我使用“a”作为最通用的class,“b”是一个它的子项,而“c”是“b”的子项。我希望“c”具有“b”和"a"的所有方法和属性,但“[=32]的部分功能=]a”被“b”覆盖,所以“c”访问被覆盖功能的唯一方法是使用原型链。 不幸的是,我的方法行不通,所以问题是:
- 在
meme()
函数中,如何避免 kalreg.proto - 有人告诉我这种访问原型的方式对代码来说很糟糕而且很危险。 在我看来,输出中不应该有"undefined",但是,有。 预期输出为:
来自 c X 的 cccccccc 测试
bbbbbbbb 测试来自 b X
aaaaaaaa 来自 X
的测试
如何实现?
谢谢!
in
meme() function
, how to avoid kalreg.proto
在确实需要从超类访问 属性 的用例中使用 super
(但请注意,这对 test
和 [=14 没有帮助=],因为它们不在超类或其 prototype
对象上,它们在使用 new c
创建的实例上;更多内容见下文)。
另外:避免__proto__
。在需要访问对象原型的极少数情况下,请使用 Object.getPrototypeOf
.
in my opinion there should be no "undefined" in output however there is. expected output is:
cccccccc test from c X
bbbbbbbb test from b X
aaaaaaaa test from a X
输出是正确的,因为您调用 mimi
的原型对象没有 test
或 testA
属性。只有使用 new c
创建的对象才具有这些属性。而且只有一个这样的对象,所以 test
将是 "test from c"
无论你调用哪个 mimi
,而 testA
将永远是 "X"
.
在评论中,您问过当每个构造函数中都有 this.test = ...
时,怎么可能只有一个 test
。完成后让我们看看内存中的内容 var kalreg = new c();
:
+−−−−−−−−−−−−+ a−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−>| (function) | +−−−>(Function.prototype) | +−−−−−−−−−−−−+ | | | __proto__ |−−+ +−−−−−−−−−−−−−+ | | prototype |−−−−−−−−−−+−>| (object) | | +−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+ | | | __proto__ |−−>... +−−−−−−−−−−−−+ | | | constructor |−−>a b−−−−−−−−−−−−−−−−−−−+−>| (function) | | | | mimi |−−>... | +−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−+ | | __proto__ |−+ +−−−−−−−−−−−−−+ | | | prototype |−−−−−−−−+−>| (object) | | | +−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+ | | | | __proto__ |−−+ +−−−−−−−−−−−−+ | | | constructor |−−>b c−−−>| (function) | | | | mimi |−−>... +−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−+ | __proto__ |−+ +−−−−−−−−−−−−−+ | | prototype |−−−−−−−+−>| (object) | | +−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+ | | | __proto__ |−+ | | constructor |−−>c +−−−−−−−−−−−−+ | | mimi |−−>... kalreg−−−>| (object) | | | meme |−−>... +−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+ | __proto__ |−−+ | test | | testA | +−−−−−−−−−−−−+
如你所见,只有kalreg
指向的对象有test
或testA
。为什么?因为在调用每个构造函数期间,this
指的是那个对象;这就是 new
和 super()
的工作原理。因此,由于 this
引用该对象,每个构造函数都执行其 this.test = ...
行,并且由于 c
中的那个是 运行 的最后一个,它“获胜”。 =57=]
您可以访问 mimi
方法的超类版本,但由于它们都显示 test
属性,因此它们都会显示 "test from c"
。要显示不同的内容,它们必须显示 不同的 属性。此外,使用 super
你只能向上一级,所以如果你想向上两级,你要么使用 a.prototype.mimi
(或明确地使用 this.__proto__.__proto__.mimi
,要么在b
调用 a
的 mimi
.
每个级别具有不同属性的示例,并且 b
提供 superMimi
因此 c
可以使用 a
的 mimi
:
class a {
constructor() {
this.testA = "test from a (this.testA)";
}
mimi() {
console.log('aaaaaaaa', this.testA);
}
}
class b extends a {
constructor() {
super();
this.testB = "test from b (this.testB)";
}
mimi() {
console.log('bbbbbbbb', this.testB)
}
superMimi() {
return super.mimi();
}
}
class c extends b {
constructor() {
super();
this.testC = "test from c (this.testC)";
}
mimi() {
console.log('cccccccc', this.testC);
}
meme() {
super.mimi(); // Uses b's version
super.superMimi(); // Uses a's version
this.__proto__.__proto__.__proto__.mimi.call(this); // Also uses a's version
var p = Object.getPrototypeOf(this);
var p2 = Object.getPrototypeOf(p);
var p3 = Object.getPrototypeOf(p2);
p3.mimi.call(this); // Also uses a's version
}
}
var kalreg = new c();
kalreg.mimi();
kalreg.meme();