JS默认参数与解构特殊场景:为何赋值0可正常执行?
关于JavaScript解构参数默认值的困惑解答
咱们一步步拆解你遇到的问题,把背后的逻辑说透:
第一种情况:无参数默认值时调用报错
先看你写的第一个函数:
var b = ({a = 1, b = 1, c = 1}) => a + b + c;
这里箭头函数的参数直接是对象解构模式,意味着调用函数时,JS会尝试把传入的参数(没传参的话就是默认的undefined)当作对象来解构。但undefined不是对象,根本没法读取它的属性,所以调用b()时自然就抛出错误了。
第二种情况:带参数默认值时的奇怪表现
再看第二个函数:
var b = ({a = 1, b = 1, c = 1} = 0) => a + b + c;
这里的= 0是给整个参数变量设置默认值,不是直接给解构的对象赋值。当你调用b()时,因为没传参,参数变量会被赋值为默认值0。接下来要对0做对象解构,这时候JS会执行一个关键操作:ToObject转换——它会把数字、字符串这类原始类型值转换成对应的包装对象,0就变成了Number {[[PrimitiveValue]]: 0}这个对象。
然后解构这个Number对象的a、b、c属性,显然这个对象里压根没有这些属性,所以就会用你定义的解构默认值1,三者相加就是3。
调用b([])时,数组本身就是对象,不需要转换。数组对象同样没有a、b、c属性,所以还是用默认值1,结果自然也是3。
关于是否等价于= {}的疑问
你问这是不是等价于var b = ({a = 1, b = 1, c = 1} = {}) => a + b + c;?
在你的这个场景下,结果确实是一样的——因为空对象{}和0转成的Number对象都没有a、b、c属性,都会触发解构默认值。但从本质上来说,二者不完全等价:
- 如果解构的是Number对象特有的属性(比如
toString),0转成的Number对象自带这个属性,而空对象没有,这时候结果就会不同。 - 比如你把函数改成
({toString = 'default'} = 0) => toString,调用b()会返回Number对象的toString方法,而如果默认值是{},则会返回'default'。
所以在你的例子里结果一致,但底层逻辑和扩展场景下是有区别的。
内容的提问来源于stack exchange,提问作者Shyam Babu
相关产品推荐
相关产品推荐

