【问题标题】:Scope of Default function parameters in javascriptjavascript中默认函数参数的范围
【发布时间】:2017-12-07 09:17:16
【问题描述】:

我正在使用 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 that variable is not defined。

Chrome 似乎在做一些优化,只创建了 1 个作用域,所有参数都设置为不可访问,并在分配后一一添加。

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

(function(a = () => b, b = 2) { return a() === 2; })();

对于我的口味来说,这似乎是一个错失的机会,我想知道规范是否强制在这里只使用 1 个作用域,或者这只是 v8 实现细节。

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

【问题讨论】:

  • missing opportunity for my taste - 这是其他人编写的语言的问题:p
  • 参数范围是它自己的范围。在函数声明表达式中,定义为参数的符号立即占主导地位。所以(a = a) 没有意义,因为左侧的a 在包含上下文中隐藏了a。

标签: javascript ecmascript-6


【解决方案1】:

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

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

(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;
  }
})();

【讨论】:

  • 所以看起来 a = a case 无论如何都不可行。如果每个默认值都在自己的范围内进行评估,则案例 a = b 可能是可行的。但这对引擎来说开销太大,因此所有参数只有 1 个作用域。看起来规范在这里很清楚。谢谢。
猜你喜欢
  • 1970-01-01
  • 2018-06-28
  • 2018-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
相关资源
最近更新 更多