javascript中默认函数参数的范围 [英] Scope of Default function parameters in javascript

查看:21
本文介绍了javascript中默认函数参数的范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究 EcmaScript 2015 的一些特性,我必须说规范很难理解.

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

(function(a = b, b = 1) { })();

而且我知道默认值可以使用外部作用域:

(function() {让 c = 1;return (function(a = c) { return a === 1; })();})();

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

(function() {让 a = 1;(函数(a = a) { })();})();(功能() {让 b = 1;(函数(a = b, b = 2) { })();})();

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

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

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

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

对我来说,这似乎是一个缺失的机会,我想知道规范是否强制在这里只使用 1 个范围,或者这只是 v8 的实现细节.

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

解决方案

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

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

(function(a = 2, b = a) { console.log(b); }());

<块引用>

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

相关部分是§9.2.12 FunctionDeclarationInstantiation.

<块引用>

我必须说规范相当难以理解.

是的,虽然它是为引擎实现者而不是程序员编写的.但是,注释基本上证实了您对优化的理解

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

你的例子基本上脱糖

(function() {让 a = arguments[0] !== undefined ?参数[0]:b,//^ 显然是一个 ReferenceErrorb = 参数[1] !== 未定义?参数[1]:1;{}})();(功能() {让 c = 1;返回(函数(){让 a = arguments[0] !== undefined ?参数[0]:c;//^ 像你想的那样工作{返回一个 === 1;}})();})();(功能() {让 a = 1;(功能() {让 a = arguments[0] !== undefined ?参数[0]:一个;//^ 显然是一个 ReferenceError{}})();})();(功能() {让 b = 1;(功能() {让 a = arguments[0] !== undefined ?参数[0]:b,//^ 仍然是一个 ReferenceErrorb = 参数[1] !== 未定义?参数[1]:2;{}})();})();(功能() {让 a = arguments[0] !== undefined ?参数[0] : () =>乙,//^ 确实有效b = 参数[1] !== 未定义?参数[1]:2;{返回 a() === 2;}})();

I'm playing with some EcmaScript 2015 features and I must say that specification is rather hard to understand.

I totally understand that this code should throw error of some kind:

(function(a = b, b = 1) { })();

And I know that default value could use outer scope:

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

But I don't understand why these examples are not good:

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

(function() {
  let b = 1;
  (function(a = b, b = 2) { })();
})();

My Chrome 59.0.3071.115 throws ReferenceError that variable is not defined.

It seems that Chrome is doing some optimization where only 1 scope is created where all parameters set as inaccessible, and they are added one by one after their assignment.

Some proof of this could be:

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

This looks like an missing opportunity for my taste and I'm wondering does specification force to use only 1 scope here or this is only v8 implementation details.

Could somebody please point me to place in specification which could clarify this?

解决方案

I don't understand why these examples are not good

Because the default initialisers are not evaluated in the parent scope, but rather inside the function scope. The parameters themselves are already in scope, so that you can do something like

(function(a = 2, b = a) { console.log(b); }());

Could somebody please point me to place in specification which could clarify this?

The relevant section is §9.2.12 FunctionDeclarationInstantiation.

I must say that specification is rather hard to understand.

Yes it is, although it's written for engine implementors not for programmers. However, the explanatory note basically confirms your understanding of the optimisation

If the function’s formal parameters do not include any default value initializers then the body declarations are instantiated in the same Environment Record as the parameters. If default value parameter initializers exist, a second Environment Record is created for the body declarations.

Your examples basically desugar to

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

这篇关于javascript中默认函数参数的范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆