在方法中的箭头函数中的箭头函数中使用' super '
Using `super` within an arrow function within an arrow function within a method
我试图弄清楚我在Node v4.1.1 (V8 v4.5.103.33)中看到的关于super
和箭头函数的一些行为是否指定的行为,如果是这样(或者确实,如果不是),在规范中,它说它应该(或不应该)在我拥有的各种情况下工作。
简而言之:在方法中的箭头函数(inner
)中使用super
在另一个箭头函数(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");
<>之前$ node test.js/道路/. js: 13超级。Show (' arg = ${arg}, x = ${x} ');^ ^ ^ ^ ^SyntaxError: 'super'关键字这里是意外的(/path/test.js:16:13)在孩子。方法(/道路/. js:到了在对象。(/道路/. js:二二13)在模块。_compile (module.js 434:26):at Object.Module._extensions. js (module.js:452:10)在模块。负载(module.js 355:32):在Function.Module。_load (module.js 310:12):at Function.Module.runMain (module.js:475:10)启动时(node.js:117:18)在node . js: 951:3之前如果你删除x
的引用,在inner
:
let inner = () => {
super.show(`arg = ${arg}`); // <== removed x from this
};
it 工作并输出:
<>之前外部:x = 42Parent#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");
输出:<>之前方法调用时,标志为falseouter2的类型:功能inner2的类型:函数Parent2#show: A: arg (false)之前但是如果我们注释掉标记为A
的行,并取消B
或C
的注释,它就会像MCVE一样失败。
更指出:
我要强调的是,您需要嵌套箭头函数。
outer
访问super
没有问题。我不想用另一个大的代码块混淆问题,但是如果你在outer
的顶部添加super.show(`outer: arg = ${arg}, x = ${x}`);
,它工作得很好。正如您所看到的,
inner
同时使用method
的参数和变量(好吧,MCVE只是使用arg),这很好,但是一旦inner
试图使用outer
的参数或变量,事情就会爆发。Babel和Traceur都非常乐意翻译V8无法运行的情况(这里和这里),但这可能只是他们得到V8正确的错误(或者,当然,反之亦然)。
与模板字符串无关;这个的pre-MCVE版本没有使用它们(并且使用了承诺,这就是为什么我们最终使用箭头中的箭头)。
我的直觉告诉我这只是一个V8的bug —毕竟,这种东西现在还为时尚早。但不管怎样,我只是想弄清楚行为应该是什么,规范是怎么说的。我试着跟随它的各种各样的章节谈论super
和"基本对象"等,坦率地说,我只是不明白它。
看来这确实是V8中的一个bug(现在已经修复了)。请注意,如果没有嵌套的箭头函数,它可以正常工作。
所以,如果我们要查看文字规范文本,看看这是否是一个错误,让我们从super
关键字本身开始:
12.3.5.3运行时语义:MakeSuperPropertyReference(propertyKey, strict)
带有propertyKey和strict参数的抽象操作MakeSuperPropertyReference执行以下步骤:
- 让环境为GetThisEnvironment().
- 如果env.HasSuperBinding()为false,抛出ReferenceError异常。
- 让actualThis为env.GetThisBinding()。
- ReturnIfAbrupt (actualThis)。
- 让baseValue为env.GetSuperBase().
- 让bv为RequireObjectCoercible(baseValue)
- ReturnIfAbrupt (bv)。
- 返回一个Reference类型的值,该值为Super Reference,基值为bv,引用名称为propertyKey, thisValue为actualThis,严格引用标志为strict。
让我们忽略大多数冗长的东西,并关注GetThisEnvironment():
8.3.2 GetThisEnvironment ()抽象操作GetThisEnvironment查找当前提供关键字this绑定的环境记录。GetThisEnvironment执行以下步骤:
- 让lex作为正在运行的执行上下文的LexicalEnvironment。
- 重复
a.让envRec成为lex的环境记录。
b.让存在为envRec.HasThisBinding()。
c.如果exists为true,返回envRec。
d.设outer为lex的外部环境引用值。
e.让lex在外部。步骤2中的循环将总是终止,因为环境列表总是以具有this绑定的全局环境结束。
现在我们知道箭头函数没有绑定到this
,它应该跳过当前函数的环境记录和立即包围它的函数。
这将在到达"常规"函数,然后按照规范检索对super
对象的引用。
Allen Wirfs-Brock, ECMAScript规范的项目编辑,似乎在几年前es-discuss邮件列表的回复中证实了这一点:
super
具有词法作用域,就像this
一样,限定在定义它的最近的封闭函数内。除了箭头函数外,所有的函数定义形式都引入了新的this
/super
绑定,所以我们可以[说]this
/super
绑定是根据最近的封闭的非箭头函数定义。
- 创建一个类似链接的按钮,并通过Javascript函数打开一个新的弹出窗口
- 将函数的上下文应用于javascript变量
- 如何在JavaScript中将字符串转换为函数引用
- 用嵌套函数和默认函数定义函数
- 使用 jQuery 的 .on 函数如何获取事件的原始元素
- 无法导出函数expressjs/requestjs中的变量
- 函数参数中的数据与指定变量之间的任何性能差异
- JQuery合并了keyup和focusout两个函数
- ES6构造函数返回基类的实例
- 监视函数从服务返回不起作用,但作用域函数起作用
- 类构造函数super()没有'我不在IE工作
- 在 Coffeescript 类的函数中指定第 n 个参数的“super”
- $super不是人力车JS中的函数错误
- 在React构造函数中调用super()做什么?
- 在方法中的箭头函数中的箭头函数中使用' super '
- 打字错误:A 'super'当类包含初始化的属性时,Call必须是构造函数中的第一个语句
- 在ES6中包装类函数和使用super的简单方法
- 如何在javascript中创建一个super函数
- 为什么我需要使用super()访问基类构造函数
- 何时需要使用super(props)将prop传递给react组件的构造函数