javascript中默认函数参数的范围

Dim*_*ich 1 javascript ecmascript-6

我正在使用一些 EcmaScript 2015 功能,我必须说该规范相当难以理解。

我完全理解这段代码应该抛出某种错误:

(function(a = b, b = 1) { })();
Run Code Online (Sandbox Code Playgroud)

我知道默认值可以使用外部范围:

(function() {
  let c = 1;
  return (function(a = c) { return a === 1; })();
})();
Run Code Online (Sandbox Code Playgroud)

但我不明白为什么这些例子不好:

(function() {
  let a = 1;
  (function(a = a) { })();
})();

(function() {
  let b = 1;
  (function(a = b, b = 2) { })();
})();
Run Code Online (Sandbox Code Playgroud)

我的 Chrome 59.0.3071.115 抛出 ReferenceError 变量未定义。

Chrome 似乎正在做一些优化,只创建 1 个范围,所有参数都设置为不可访问,并且在分配后将它们一一添加。

这方面的一些证据可能是:

(function(a = () => b, b = 2) { return a() === 2; })();
Run Code Online (Sandbox Code Playgroud)

就我的口味而言,这看起来像是一个缺失的机会,我想知道规范是否强制在此处仅使用 1 个范围,或者这只是 v8 实现细节。

有人可以指出我在规范中的位置可以澄清这一点吗?

Ber*_*rgi 6

\n

我不明白为什么这些例子不好

\n
\n\n

因为默认初始化器不是在父作用域中计算的,而是在函数作用域内计算的。参数本身已经在范围内,因此您可以执行类似的操作

\n\n
(function(a = 2, b = a) { console.log(b); }());\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

有人可以指出我在规范中的位置可以澄清这一点吗?

\n
\n\n

相关部分是\xc2\xa79.2.12 FunctionDeclarationInstantiation

\n\n
\n

我必须说这个规范很难理解。

\n
\n\n

是的,尽管它是为引擎实现者而不是程序员编写的。不过,注释基本上证实了你对优化的理解

\n\n

如果函数\xe2\x80\x99s 形式参数不包含任何默认值初始值设定项,则主体声明将在与参数相同的环境记录中实例化。如果存在默认值参数初始值设定项,则会为主体声明创建第二个环境记录。

\n\n

你的例子基本上脱糖到

\n\n
(function() {\n  let a = arguments[0] !== undefined ? arguments[0] : b,\n//                                                    ^ clearly a ReferenceError\n      b = arguments[1] !== undefined ? arguments[1] : 1;\n  {\n  }\n})();\n\n(function() {\n  let c = 1;\n  return (function() {\n    let a = arguments[0] !== undefined ? arguments[0] : c;\n//                                                      ^ works as you\'d think\n    {\n      return a === 1;\n    }\n  })();\n})();\n\n(function() {\n  let a = 1;\n  (function() {\n    let a = arguments[0] !== undefined ? arguments[0] : a;\n//                                                      ^ again clearly a ReferenceError\n    {\n    }\n  })();\n})();\n\n(function() {\n  let b = 1;\n  (function() {\n    let a = arguments[0] !== undefined ? arguments[0] : b,\n//                                                      ^ still a ReferenceError\n        b = arguments[1] !== undefined ? arguments[1] : 2;\n    {\n    }\n  })();\n})();\n\n(function() {\n  let a = arguments[0] !== undefined ? arguments[0] : () => b,\n//                                                          ^ works indeed\n      b = arguments[1] !== undefined ? arguments[1] : 2;\n  {\n    return a() === 2;\n  }\n})();\n
Run Code Online (Sandbox Code Playgroud)\n