T.J*_*der 20 javascript ecmascript-2015
我试图弄清楚我在Node v4.1.1(V8 v4.5.103.33)中看到的关于super和箭头函数的某些行为是否是指定行为,如果是这样(或者实际上,如果不是),它在哪里它说它应该(或不应该)在我所拥有的各种情况下工作的规范.
简言之:使用super箭头函数(inner)内的另一个箭头功能(outer)内的方法的工作,除非 outer有参数还是变量inner即使引用,inner引用参数或变量method.我想知道规范对此的说法:它是否应该一直有效,即使在V8失败的情况下?没有时间?只有在V8目前让它工作的特定情况下,而不是它不在哪里?
这是一个MCVE:
"use strict";
class Parent {
show(msg) {
console.log(`Parent#show: ${msg}`);
}
}
class Child extends Parent {
method(arg) {
let outer = (x) => {
console.log(`outer: x = ${x}`);
let inner = () => {
super.show(`arg = ${arg}, x = ${x}`);
};
inner();
};
outer(42);
}
}
new Child().method("arg");
Run Code Online (Sandbox Code Playgroud)
那失败了:
$ node test.js
/path/test.js:13
super.show(`arg = ${arg}, x = ${x}`);
^^^^^
SyntaxError: 'super' keyword unexpected here
at outer (/path/test.js:16:13)
at Child.method (/path/test.js:18:9)
at Object. (/path/test.js:22:13)
at Module._compile (module.js:434:26)
at Object.Module._extensions..js (module.js:452:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:475:10)
at startup (node.js:117:18)
at node.js:951:3
如果您删除提及x这是在inner:
let inner = () => {
super.show(`arg = ${arg}`); // <== removed x from this
};
Run Code Online (Sandbox Code Playgroud)
它的工作原理和输出:
outer: x = 42 Parent#show: arg = arg
为了向自己证明"工作"的情况不是函数被优化掉了,我将它们从方法中退出并调用它们.这是一个稍微复杂的案例(请注意评论); 这个版本有效:
"use strict";
class Parent2 {
show(msg) {
console.log(`Parent2#show: ${msg}`);
}
}
class Child2 extends Parent2 {
method(arg) {
let flag = Math.random() < 0.5;
console.log(`method called with ${arg}, flag is ${flag}`);
let x = "A"; // **A**
let outer2 = (/*x*/) => { // **B**
//let x = "C"; // **C**
let inner2 = () => {
super.show(`${x}: ${arg} (${flag})`);
};
return inner2;
};
return outer2;
}
}
let o = new Child2().method("arg");
console.log(`type of outer2: ${typeof o}`);
let i = o();
console.log(`type of inner2: ${typeof i}`);
i("B");
Run Code Online (Sandbox Code Playgroud)
输出:
method called with arg, flag is false type of outer2: function type of inner2: function Parent2#show: A: arg (false)
但是,如果我们注释掉线标记A并取消要么B或者C,它像MCVE确实失败.
更多说明:
我应该强调你需要嵌套箭头函数.outer访问没有问题super.我不想用另一个大的代码块来混淆这个问题,但是如果你super.show(`outer: arg = ${arg}, x = ${x}`);在顶部添加outer,它就可以了.
正如你所看到的,inner使用了一个参数和一个变量method(好吧,MCVE只使用一个arg),这很好,但是一旦inner尝试使用参数或变量outer,事情就会爆炸.
Babel和Traceur都很高兴能够解释V8无法运行的情况(这里和这里),但这可能只是他们弄错了V8正确(或者,反之亦然).
它与模板字符串无关; 这个前MCVE版本没有使用它们(并且确实使用了promises,这就是我们最终用箭头指向箭头的方式).
需要强调的是,问题是这里指定的行为是什么,以及指定的规范中的位置.
我的直觉告诉我这只是一个V8错误 - 毕竟,这个东西是早期的,公平的'nuff.但无论哪种方式,我只想弄清楚行为应该是什么,规范是什么.我试图跟随它的各种各样的部分谈论super和"基础对象"等,坦率地说,我只是没有得到它.
Qan*_*avy 10
看来这确实是V8中的一个错误(现在已经修复).请注意,如果没有嵌套箭头功能,它可以正常工作.
因此,如果我们要查看文字规范文本以查看这是否是一个错误,那么让我们从super关键字本身开始:
12.3.5.3运行时语义:MakeSuperPropertyReference(propertyKey,strict)
带有参数propertyKey和strict的抽象操作MakeSuperPropertyReference执行以下步骤:
- 让env成为GetThisEnvironment().
- 如果env.HasSuperBinding()为false,则抛出ReferenceError异常.
- 让actualThis为env.GetThisBinding().
- ReturnIfAbrupt(actualThis).
- 让baseValue为env.GetSuperBase().
- 设bv为RequireObjectCoercible(baseValue).
- ReturnIfAbrupt(BV).
- 返回Reference类型的值,它是一个超级引用,其基值为bv,其引用名称为propertyKey,其thisValue为actualThis,其严格引用标志为strict.
让我们忽略大多数罗嗦的东西并担心GetThisEnvironment():
8.3.2 GetThisEnvironment()
抽象操作GetThisEnvironment找到当前提供关键字this绑定的环境记录.GetThisEnvironment执行以下步骤:
- 让lex成为正在运行的执行上下文的LexicalEnvironment.
- 重复
一次.让envRec成为lex的EnvironmentRecord.
湾 让存在是envRec.HasThisBinding().
C.如果exists为true,则返回envRec.
d.设外为lex的外部环境参考值.
即 让lex成为外在的.注意步骤2中的循环将始终终止,因为环境列表始终以具有此绑定的全局环境结束.
现在我们知道箭头函数没有绑定this,它应该跳过当前函数的环境记录和立即封闭它的函数.
super根据规范,这将在到达"常规"函数时停止并继续按预期检索对象的引用.
ECMAScript规范的项目编辑Allen Wirfs-Brock似乎证实,这是几年前在es-discuss邮件列表的回复中的意图:
super是词法范围的,就像this最接近定义它的封闭函数一样.除了箭头函数之外的所有函数定义形式都引入了新的this/super绑定,因此我们可以根据最接近的非箭头函数定义来[绑定]this/super绑定.