【JavaScript】函数参数默认值为函数时,默认值函数的作用域问题

266 阅读2分钟

关键词:函数默认参数,函数参数作用域

代码

var x = 1;

function foo(x, yoo = function () { x = 3; console.log(x); }) {
  console.log(x);
  var x = 2;
  yoo();
  console.log(x);
}

foo();
console.log(x);

// 结果依次打印:undefined、3、2、1

解释

ES6引入了函数默认参数,因此可以用babel工具转换为ES5来说明,转换结果如下:

"use strict";

var x = 1;

function foo(x) {
  var yoo =
    arguments.length > 1 && arguments[1] !== undefined
      ? arguments[1]
      : function () { x = 3; console.log(x); };
        
  return (function (x) {
    console.log(x); // undefined
    var x = 2;
    yoo(); // 3
    console.log(x); // 2
  })(x);
}

foo();
console.log(x); // 1

从转换结果可以看出,函数具有默认参数的情况下,会被转换为一种新形式,即,具有默认参数的形参会作为函数的内部变量,然后将默认值赋值给这个变量,同时将原函数体放入一个新的函数,作为新形式函数的返回值。

因此,函数foo参数yoo实际上被声明为函数foo内部的变量,并将后面的匿名函数赋值给函数yoo。此处就是在函数foo内部声明了一个新的函数yoo,因此函数yoo的父作用域在函数foo内。由于函数作用域在函数声明时就已经确定了,所以函数yoox=3改变的是函数foo的参数x传入的值。

同时,原函数被封装为立即执行函数,并将x作为实参传入,最后返回。个人感觉这个操作也太巧妙了。

通过 Babel转换工具还能看出,如果函数参数用了解构也会转换为新形式。

参考链接

  1. Sunshine_Lin:看似简单的题,席卷几十个前端群,王红元老师都亲自出面解答
  2. 切图仔小源:函数参数默认值带来的作用域问题
  3. MDN: Scope Effects
  4. Babel转换工具