在工作中发现了一个对于函数对象参数处理有趣发现。函数目标是对于传入的对象参数进行一定处理(包含添加新属性)后作为下一步处理的条件。

原有的逻辑大概如下:

1
2
3
4
const fun = (obj) => {
obj['param'] = 'hello';
console.log(obj);
}

乍看如果按要求传参,没什么问题(这里先只考虑函数逻辑,不考虑健壮性)。
但当在程序中运行时,出现了如下报错:

1
TypeError: Cannot set property 'param' of undefined

这一步,不用多想,有可能没传参,加个默认参数:

1
2
3
4
const fun = (obj = {}) => {
obj['param'] = 'hello';
console.log(obj);
}

再次运行程序,又出现了如下报错:

1
TypeError: Cannot set property 'param' of null

此时,我脑中就是一个黑人问号脸,还有主动传 null 的地方???看了下屎山,也觉得不奇怪了。继续改,此时想到如果使用判断,会增加代码量,不够简练。

1
2
3
4
5
6
// 如果使用判断,以下是我能想到的最简练的方法,但感觉依然不够简练
const fun = (obj) => {
obj = obj || {};
obj['param'] = 'hello';
console.log(obj);
}

就又想到了展开运算符 ...

1
2
3
4
const fun = (obj) => {
obj = { ...obj, param: 'hello' };
console.log(obj);
}

嗯,完美了。

此时又联想到展开运算符对于数组的表现是什么样的呢?

1
2
3
4
const fun = (arr) => {
arr = [ ...arr, 0 ];
console.log(arr);
}

此时如果不传参或是传参为 null 会得到如下报错:

1
2
3
4
// 不传参
TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
// 传参为null
TypeError: object null is not iterable (cannot read property Symbol(Symbol.iterator))

由此可见,在对象中使用展开运算符时,会忽略处理 undefinednull,但在数组中使用展开运算符对 undefinednull 处理时会抛出异常。