今天早上我遇到了tweet from Šime Vidas,他提出了在对象文字中使用super
的以下可能性:
let A = {
run() {
console.log('A runs');
}
};
let B = {
run() {
super.run();
}
};
Object.setPrototypeOf(B, A);
B.run(); // A runs
这很有效,而且在Firefox和Chrome中分配B.__proto__ = A;
似乎也可以正常工作。
所以我想我可以对Object.create
:
let A = {
run() {
console.log('A runs');
}
};
let B = Object.create(A);
B.run = function() { super.run() };
不幸的是,这导致两个Firefox都出错:
SyntaxError:使用超级属性访问仅在方法或方法中的eval代码中有效
和Chrome:
未捕获的SyntaxError:'super'关键字在这里意外
当我尝试将属性描述符对象传递给Object.create
的第二个参数时,会发生同样的情况。
在语义上,它们似乎都与我相等,所以我不太确定发生了什么(是因为对象字面意思?)。
现在我想知道,这个标准行为是否准确定义(规格参考赞赏)? Object.create
是否缺少某些实现,或者对象文字是否应该首先起作用?
答案 0 :(得分:5)
ES2015规范的编辑Allen Wirfs-Brock非常友好answer my question on twitter。
为什么这是一个错误?
超级属性引用只能出现在类def或obj lit http://tc39.github.io/ecma262/#sec-function-definitions-static-semantics-early-errors
类中的“简明方法”中
在规范的那一部分,静态语义:早期错误,有四点似乎是相关的:
因此,超级属性调用既不允许在函数参数中,也不在常规函数体中。因此我的问题。
为什么需要使用方法定义?
原因是
super
需要从方法到其包含对象的反向链接。 http://tc39.github.io/ecma262/#sec-runtime-semantics-definemethod
意思是,如果我在方法中有超级调用,并且我将该方法分配给另一个变量,它仍然必须工作:
let B = {
run() {
super.run();
},
walk() {
console.log(typeof this.run);
}
};
var run = B.run;
run(); // the 'super' binding still works, thanks to the internal MakeMethod
var walk = B.walk;
walk(); // 'undefined': the 'this' binding on the other hand is lost, as usual
这是在定义方法语义的部分的第7步中指定的,当前对于对象的常规赋值不会发生这种情况:
这些语义将来会改变吗?
反向链接至关重要。动态设置它的方法被考虑了,可能会再次出现。遗漏了b / c错误
所以有可能像.toMethod
这样可以设置对象super
引用的东西可能会被引入到语言中,这使得我的初始示例可以Object.create
成为可能
答案 1 :(得分:1)
我的意思是你可以这样做:
let A = {
run() {
console.log('A runs');
}
};
let B = {
run() {
super.run();
}
};
Object.setPrototypeOf(B, A);
let C = Object.create(B);
C.run(); //A runs
顺便说一句,这也失败了:
let A = {
run() {
console.log('A runs');
}
};
let B = {
run: function() {
super.run(); // 'super' keyword unexpected here
}
};
Object.setPrototypeOf(B, A);
B.run();
答案 2 :(得分:1)
你的答案涵盖了大部分内容。 super
调用仅允许在方法中使用,因为方法与声明它们的对象紧密相关。那就是说,你最好的选择就是
let B = {
__proto__: A,
run(){
super.run();
}
};
以声明方式创建一个以A
为原型的对象,而不需要对Object.setPrototypeOf(B, A).
进行潜在的去优化调用