请考虑这样的代码:
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 "作为最通用的课程," b "这是一个孩子," c "这是" b "的孩子。我想" c "拥有" b "的所有方法和属性和" a"但是" a "的功能的一部分?被" b "覆盖所以唯一的方法" c "可能有权访问被覆盖的功能是使用原型链。 不幸的是,我的方式不起作用所以问题是:
meme()
函数中,如何避免使用kalreg.proto - 我被告知这种访问原型的方式对代码来说是危险且危险的。在我看来,应该没有" undefined"然而,在输出中,有。 预期的输出是:
来自c X的cccccccc测试
来自b X的bbbbbbbb测试
来自X的aaaaaaaa测试
如何实现它?
谢谢!
答案 0 :(得分:3)
在
meme() function
中,如何避免使用kalreg。 proto
对于您确实需要从超类访问属性的用例,请使用super
(但请注意,这对test
和testA
无效,因为这些不是在超类或其prototype
对象上,它们位于使用new c
创建的实例上;更多内容在下面。)
另外:避免__proto__
。在极少数需要访问对象原型的情况下,请使用Object.getPrototypeOf
。
在我看来,输出中应该没有“未定义”但是有。预期产出是:
来自c X的cccccccc测试
来自b X的bbbbbbbb测试
来自X的aaaaaaaa测试
输出正确,因为您调用mimi
的原型对象没有test
或testA
属性。只有使用new c
创建的对象才具有这些属性。并且只有一个这样的对象,因此test
无论您拨打"test from c"
哪个mimi
都是testA
,"X"
始终为test
。
在评论中,您已经询问当每个构造函数中包含this.test = ...
时,如何只能有一个var kalreg = new c();
。一旦你完成kalreg
,我们就看一下记忆中的内容:
+−−−−−−−−−−−−+ 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 | +−−−−−−−−−−−−+
如您所见,只有对象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
的{{1}}。
每个级别具有不同属性的示例,并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();
:
{{1}}