考虑以下两段代码:
1 2 3 4 5 6 7
| let x = 1, z = 2
function foo(w = x + 1, y = w + 1, z = z + 1) { console.log(x, y, z) } foo()
|
1 2 3 4 5 6 7
| let x = 1, z = 2
function foo(w = x + 1, y = w + 1, z) { console.log(x, y, z) } foo()
|
第一段会报错:ReferenceError: z is not defined
第二段不报错,输出:1 3 undefined
然后就很不解,ES6 的函数的参数在进行默认值赋值时是基于一种怎样的规则?对第一个 w 赋值,找 x,也是找的其上层作用域的 x,为什么找 z 的时候就报错了,z 明明在其上层作用域也存在!为了找到原因,用 babel 将其编译,编译后的结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| "use strict";
var x = 1, z = 2;
function foo() { var w = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : x + 1; var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : w + 1; var z = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : z + 1;
console.log(x, y, z); } foo();
|
想到了 ES5 的函数和变量的声明提升,上述代码会被引擎提前处理成如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var x, z; x = 1 z = 2;
function foo() { var w, y, z;
w = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : x + 1; y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : w + 1; z = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : z + 1;
console.log(x, y, z); } foo();
|
编译器对 w 进行 LHS 查询时,会对 x 进行 RHS 查询,从当前作用域开始一直往上查找,当前作用域中没有 x,上层作用域中 x=1,即 w=2
编译器对 y 进行 LHS 查询时,会对 w 进行 RHS 查询,在当前作用域中找到了 w=2,所以 y=3
编译器对 z 进行 LHS 查询时,会对 z 进行 RHS 查询,虽然上层作用域中有 z,但还是会从当前作用域开始一直往上查找,当前作用域中有 z,z 虽然声明但未进行赋值,即 z===undefined
遇到 ES6 中不理解的语法糖时,一定要先将其转成熟悉的 ES5,了解问题背后的真相和本质