我在javascript项目中有几个函数,它们接受一个对象作为参数,并期望通过一些更改返回该对象的副本。我试图使这些函数不可变,但是参数可以是对象或数组,因此我不能只使用Object.assign({}, original)
或{...original}
。
相反,我提出了两个选择:
let doSomething = function doSomething(original) {
let ret = Object.assign(Array.isArray(original) ? [] : {}, original);
//OR
let ret = Array.isArray(original) ? [...original] : {...original};
//OR
let ret = Object.assign(new (original.constructor), original);
//OR
let ret;
if(Array.isArray(original))
ret = original.slice();
else
ret = Object.assign({}, original);
//make changes
return ret;
}
在这四种方法中,我偏爱第三种方法,只是因为它支持任何类型的对象(不是我打算使用除Objects或Arrays之外的任何方法),但是它感觉很“聪明”
在四种方法中,哪种方法最易于阅读?还是有另一种首选的方式可以复制任何类型的对象?
答案 0 :(得分:2)
选项#1,#2和#4的功能完全相同。至于可读性,我的投票是第二名-最短和最清晰。
选项3还会重新创建在这种情况下不需要的构造函数/原型链。它将允许运行copiedObj instanceof OriginalObjectClass
之类的检查。但是,一旦构造函数期望一些参数(并且不会明显得到它们),它也可能会失败。因此,在您的情况下,这看起来很危险,但却无济于事。
我也完全同意D Lowther,最好从递归函数中提取克隆本身。
但是我想您不仅要克隆某个对象,而且还要递归处理克隆的嵌套属性。这样,您还需要检查此对象或数组,对吗?因此,与其分别克隆数组然后再克隆其成员,不如使用.map
在一行中完成,就更容易了:
function cloneRecursively(originalItem) {
let clonedItem = {...originalItem};
clonedItem.children = (clonedItem.children || []).map(cloneRevursively);
return clonedItem;
}
答案 1 :(得分:1)
您可以使用constructor
方法代替new (original.constructor)
!
由于您的参数可以是object
或array
,因此可以这样写:
let ret = Object.assign(original.constructor(), original)
这样调用,将返回一个空的object
或array
。
请注意,如果您的参数不是普通的JS object
,则使用constructor
可能会失败或返回意外内容