关键词:函数默认参数,函数参数作用域
代码
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内。由于函数作用域在函数声明时就已经确定了,所以函数yoo内x=3改变的是函数foo的参数x传入的值。
同时,原函数被封装为立即执行函数,并将x作为实参传入,最后返回。个人感觉这个操作也太巧妙了。
通过 Babel转换工具还能看出,如果函数参数用了解构也会转换为新形式。