我正在使用一些EcmaScript 2015功能,我必须说规范很难理解。
我完全理解这段代码应该抛出某种错误:
(function(a = b, b = 1) { })();
我知道默认值可以使用外部范围:
(function() {
let c = 1;
return (function(a = c) { return a === 1; })();
})();
但我不明白为什么这些例子不好:
(function() {
let a = 1;
(function(a = a) { })();
})();
(function() {
let b = 1;
(function(a = b, b = 2) { })();
})();
我的Chrome 59.0.3071.115会抛出ReferenceError,表明该变量未定义。
Chrome似乎正在进行一些优化,只创建了一个范围,其中所有参数都设置为无法访问,并且在分配后逐个添加。
这方面的一些证据可能是:
(function(a = () => b, b = 2) { return a() === 2; })();
这看起来像是一个缺少我的口味的机会,我想知道规范强制在这里只使用1个范围,或者这只是v8实现细节。
有人可以请我指出可以澄清这个问题的规范吗?
答案 0 :(得分:3)
我不明白为什么这些例子不好
因为默认初始化程序不在父作用域中求值,而是在函数作用域内求值。参数本身已经在范围内,因此您可以执行类似
的操作(function(a = 2, b = a) { console.log(b); }());
有人可以请我指出可以澄清这个问题的规范吗?
相关部分为§9.2.12 FunctionDeclarationInstantiation。
我必须说规范很难理解。
是的,虽然它是为引擎实现者而不是为程序员编写的。但是,解释性说明基本上证实了您对优化的理解
如果函数的形式参数不包含任何默认值初始值设定项,则在与参数相同的环境记录中实例化体声明。如果存在默认值参数初始值设定项,则会为正文声明创建第二个环境记录。
你的例子基本上是免费的
(function() {
let a = arguments[0] !== undefined ? arguments[0] : b,
// ^ clearly a ReferenceError
b = arguments[1] !== undefined ? arguments[1] : 1;
{
}
})();
(function() {
let c = 1;
return (function() {
let a = arguments[0] !== undefined ? arguments[0] : c;
// ^ works as you'd think
{
return a === 1;
}
})();
})();
(function() {
let a = 1;
(function() {
let a = arguments[0] !== undefined ? arguments[0] : a;
// ^ again clearly a ReferenceError
{
}
})();
})();
(function() {
let b = 1;
(function() {
let a = arguments[0] !== undefined ? arguments[0] : b,
// ^ still a ReferenceError
b = arguments[1] !== undefined ? arguments[1] : 2;
{
}
})();
})();
(function() {
let a = arguments[0] !== undefined ? arguments[0] : () => b,
// ^ works indeed
b = arguments[1] !== undefined ? arguments[1] : 2;
{
return a() === 2;
}
})();