的JavaScript - 原型链
请考虑这样的代码:的JavaScript - 原型链
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
我的目标逻辑让我用“一个”为最通用类,作为小孩的“b”,作为“b”的小孩的“c”。我想“Ç”拥有的“b”和“a”而是功能的一部分“一个”被覆盖“b”所以唯一的办法“Ç”所有方法和属性可能有权访问覆盖的功能是使用原型链。 不幸的是,我的路行不通,因此问题是:
- 在
meme()
功能,如何避免kalreg.proto - 我已经告诉访问原型的这样的方式是邪恶和危险的代码。 在我看来,输出中应该没有“未定义”,但是,有。 预期的输出结果是:从B X从X
如何实现从C X
CCCCCCCC测试
BBBBBBBB测试
AAAAAAAA测试?
谢谢!
in
meme() function
,如何避免kalreg。 原
使用super
的使用情况下,你确实需要访问从超类的属性(但要注意,不会与test
和testA
帮助,因为这些都不是在超或它的prototype
对象,它们使用new c
创建的实例;更多内容在下面)。
另外:避免__proto__
。在需要访问对象原型的罕见情况下,请使用Object.getPrototypeOf
。
在我看来,应该没有“未定义”的输出,但是有。预期输出是:从B X选自C X
CCCCCCCC测试
BBBBBBBB测试从X
的输出是正确
AAAAAAAA测试,因为原型对象在其上”重新拨打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
中的那个是最后一个运行的对象,因此它“获胜”。
您可以访问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();
对象如何可能没有this.test每个类是否在它们的构造函数中定义了this.test? – Kalreg
您可否详细说明如何在'meme()'方法中使用'super'来完成OPs的目标。 – Adam
@亚当:完成,感谢您将它挂起,我的意思是回到那个并忘记。 :-) –