另一个 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 43foo( undefined ); // 42 43foo( 5 ); // 5 6foo( void 0, 7 ); // 42 7foo( 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 undefinedfoo( 10 ); // 1 10 11 10 undefinedfoo( 10, undefined ); // 2 10 11 10 undefinedfoo( 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
