5.5 函数参数
另一个 TDZ 违规的例子是 ES6 中的参数默认值(参见本系列的《你不知道的 JavaScript(下卷)》的“ES6 & Beyond”部分):
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 。详情请参见第 4 章。
对 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)
因此,在开发中不要依赖这种关联机制。实际上,它是 JavaScript 语言引擎底层实现的一个抽象泄漏(leaky abstraction),并不是语言本身的特性。
arguments 数组已经被废止(特别是在 ES6 引入剩余参数 ... 之后,参见本系列的《你不知道的 JavaScript(下卷)》的“ES6 & Beyond”部分),不过它并非一无是处。
在 ES6 之前,获得函数所有参数的唯一途径就是 arguments 数组。此外,即使将命名参数和 arguments 数组混用也不会出错,只需遵守一个原则,即不要同时访问命名参数和其对应的 arguments 数组单元 。
function foo(a) { console.log( a + arguments[1] ); // 安全! } foo( 10, 32 ); // 42
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论