另一个 TDZ 违规的例子是 ES6 中的参数默认值
var b = 3;
function foo( a = 42, b = a + b + 5 ) {
// ..
}
b = a + b + 5
在参数b
(=
右边的b
,而不是函数外的那个)的TDZ中访问b
,所以会出错。而访问 a
却没有问题,因为此时刚好跨出了参数 a
的 TDZ。
在 ES6 中,如果参数被省略或者值为 undefined
,则取该参数的默认值:
function foo( a = 42, b = a + 1 ) {
console.log( a, b );
}
foo(); // 42 43
foo( undefined ); // 42 43
foo( 5 ); // 5 6
foo( void 0, 7 ); // 42 7
foo( null ); // null 1
表达式 a + 1 中 null 被强制类型转换为 0
对 ES6 中的参数默认值而言,参数被省略或被赋值为 undefined
效果都一样,都是取该参数的默认值。然而某些情况下,它们之间还是有区别的:
function foo( a = 42, b = a + 1 ) {
console.log(
arguments.length, a, b,
arguments[0], arguments[1]
);
}
foo(); // 0 42 43 undefined undefined
foo( 10 ); // 1 10 11 10 undefined
foo( 10, undefined ); // 2 10 11 10 undefined
foo( 10, null ); // 2 10 null 10 null
虽然参数 a
和 b
都有默认值,但是函数不带参数时,arguments
数组为空。相反,如果向函数传递 undefined
值,则 arguments
数组中会出现一个值为 undefined
的单
元,而不是默认值。
ES6 参数默认值会导致 arguments
数组和相对应的命名参数之间出现偏差,ES5 也会出现 这种情况:
function foo(a) {
a = 42;
console.log( arguments[0] );
}
foo( 2 ); // 42 (linked)
foo(); // undefined (not linked)
向函数传递参数时,arguments
数组中的对应单元会和命名参数建立关联(linkage)以得到相同的值。相反,不传递参数就不会建立关联。但是,在严格模式中并没有建立关联这一说:
function foo(a) {
"use strict";
a = 42;
console.log( arguments[0] );
}
foo( 2 ); // 2 (not linked)
foo(); // undefined (not linked)
因此,在开发中不要依赖这种关联机制。实际上,它是 js 语言引擎底层实现的一 个抽象泄漏(leaky abstraction),并不是语言本身的特性。arguments
数组已经被废止(特别是在 ES6 引入剩余参数...
之后),在 ES6 之前,获得函数所有参数的唯一途径就是 arguments
数组。此外,即使将命名参数和 arguments
数组混用也不会出错,只需遵守一个原则,即不要同时访问命名参数和其对应的 arguments
数组单元。
function foo(a) {
console.log( a + arguments[1] ); // 安全!
}
foo( 10, 32 ); // 42