`this`如何在默认参数中工作?

时间:2015-06-17 20:20:47

标签: javascript ecmascript-6 default-parameters

所以...ES6¹(几个小时前恰好是标准化的)为类似于PHP,Python等的函数带来了默认参数。我可以做类似的事情:

function foo (bar = 'dum') {
    return bar;
}

foo(1); // 1
foo(); // 'dum'
foo(undefined); // 'dum'

MDN表示在调用时评估参数的默认值。这意味着每次调用函数时,都会再次计算表达式'dum'(除非实现执行了一些我们不关心的奇怪优化)。

我的问题是,this如何发挥作用?

let x = {
  foo (bar = this.foo) {
    return bar;
  }
}

let y = {
  z: x.foo
}

x.foo() === y.z(); // what?

babel转换器目前正在评估它为false,但我没有得到它。如果他们真的在通话时评估,那么:

let x = 'x from global';

function bar (thing = x) {
  return thing;
}

function foo () {
  let x = 'x from foo';
  return bar();
}

bar() === foo(); // what?

babel转换器目前正在评估它为true,但我没有得到它。为什么barx内部调用foo时未foo

<子> 1 - 是的我知道它是ES2015 2 - Example A
3 - Example B

2 个答案:

答案 0 :(得分:11)

  

我的问题是,this如何发挥作用?我不明白。它们是否真的在通话时进行评估?

是的,在呼叫时评估参数初始值设定项。 It's complicated,但步骤基本如下:

  1. 在堆栈上建立new execution context
    在被调用函数的“闭包范围”中使用new environment
  2. 如有必要,可以thisBinding is initialised
  3. Declarations are instantiated
    1. 创建参数名称的可变绑定
    2. 如有必要,创建一个arguments对象绑定
    3. 参数列表中的bindings are iteratively initialised(包括所有解构等)
      在此过程中,initialisers are evaluated
    4. 如果涉及任何关闭,则插入新环境
    5. 创建函数体中声明的变量的可变绑定(如果尚未通过参数名称完成)并使用undefined初始化
    6. 创建函数体中letconst变量的绑定
    7. 函数的绑定(来自正文中的函数声明)使用实例化函数
    8. 进行初始化
  4. 最后是body of the function is evaluated
  5. 因此,参数初始化者可以访问调用的thisarguments,以及之前初始化的其他参数,以及其“上限”词法范围内的所有内容。它们不受函数体中声明的变量的影响(尽管它们受所有其他参数的影响,即使它们的时间死区也是如此)。

      

    怎么样:

    function bar (thing = x) {}
    {
      let x = 'x from foo';
      return bar();
    }
    
         

    我不明白。为什么bar在调用时不会从x获取foo   在foo内?

    因为xbar无法访问的本地变量。我们很幸运他们是not dynamically scoped!参数初始化程序不在调用站点评估,而是在被调用函数的作用域内评估。在这种情况下,x标识符将解析为全局x变量。

答案 1 :(得分:0)

当他们说'#34;在通话时评估#34;时,我认为他们指的是按姓名调用表达。以下是babel如何输出您的第三个例子:

'use strict';

var x = 'x from global';

function bar() {
  var thing = arguments[0] === undefined ? x : arguments[0];

  return thing;
}

function foo() {
  var x = 'x from foo';
  return bar();
}

bar() === foo(); // what?

由于var x是在bar的词法范围内从全局范围继承的,因此它是使用它的范围。

现在,请考虑以下事项:

let i = 0;

function id() {
  return i++;
}

function bar (thing = id()) {
  return thing;
}

console.info(bar() === bar()); // false

哪个转化为

"use strict";

var i = 0;

function id() {
  return i++;
}

function bar() {
  var thing = arguments[0] === undefined ? id() : arguments[0];

  return thing;
}

console.info(bar() === bar()); // false

注意这里,id在函数内部被称为,而不是在函数定义时被缓存和记忆,因此调用 - 按名称而不是按值调用。

所以行为 在第二个例子中实际上是正确的。在y.foo查找时,Javascript中没有this,因为y.z()动态作用域(即它根据给定函数调用的接收者而有所不同) this.foo,它会在y中查找,y.z()将返回undefined,而x.foo()只返回foo函数本身。

如果您执行想要绑定到接收者,则可以在分配时将foo绑定到x。然后它应该按预期工作。

对不起,如果有任何不清楚的话;请在评论中告诉我,我很乐意澄清! :)