如何克隆使用下划线的对象数组?

#!/usr/bin/env node var _ = require('underscore'); var a = [{f: 1}, {f:5}, {f:10}]; var b = _.clone(a); b[1].f = 55; console.log(JSON.stringify(a)); 

这导致:

 [{"f":1},{"f":55},{"f":10}] 

克隆似乎不工作! 所以我RTFM,看到这个:

http://underscorejs.org/#clone

创build对象的浅拷贝克隆。 任何嵌套的对象或数组将被引用复制,而不是重复。

所以_.clone是相当无用的。 有没有办法实际复制对象的数组?

那么,有一个窍门! 如果克隆没有“克隆”嵌套对象,则可以通过在地图调用中显式克隆每个对象来强制它! 喜欢这个:

 #!/usr/bin/env node var _ = require('underscore'); var a = [{f: 1}, {f:5}, {f:10}]; var b = _.map(a, _.clone); // <---- b[1].f = 55; console.log(JSON.stringify(a)); 

打印:

 [{"f":1},{"f":5},{"f":10}] 

好极了! a是不变的! 我现在可以编辑b我喜欢!

从Github上的问题中提取的另一个解决scheme,可以与任何级别的嵌套数据一起工作,并且不需要下划线:

 JSON.parse(JSON.stringify(obj)) 

FWIW,lodash有一个cloneDeep函数:

这个方法就像_.clone,只是recursion地克隆了值。

下划线API参考 :

_.toArray(list)_.toArray(list)创build一个真正的数组(任何可以迭代的东西)。 用于转换参数对象。

…或者在这种情况下, 克隆一个数组。 尝试这个:

 var _ = require('underscore'); var array1 = [{a:{b:{c:1}}},{b:{c:{a:2}}},{c:{a:{b:3}}}]; var array2 = _.toArray(array1); console.log(array1 === array2); --> false console.log(array1[0] === array2[0]); --> true 

以下是史蒂夫评论下面创build的附录-thx

一个香草的JS(或使用_.clone如果想要的) 深入克隆recursion助手 :

 function clone(thing, opts) { var newObject = {}; if (thing instanceof Array) { return thing.map(function (i) { return clone(i, opts); }); } else if (thing instanceof Date) { return new Date(thing); } else if (thing instanceof RegExp) { return new RegExp(thing); } else if (thing instanceof Function) { return opts && opts.newFns ? new Function('return ' + thing.toString())() : thing; } else if (thing instanceof Object) { Object.keys(thing).forEach(function (key) { newObject[key] = clone(thing[key], opts); }); return newObject; } else if ([ undefined, null ].indexOf(thing) > -1) { return thing; } else { if (thing.constructor.name === 'Symbol') { return Symbol(thing.toString() .replace(/^Symbol\(/, '') .slice(0, -1)); } // return _.clone(thing); // If you must use _ ;) return thing.__proto__.constructor(thing); } } var a = { a: undefined, b: null, c: 'a', d: 0, e: Symbol('a'), f: {}, g: { a:1 }, h: [], i: [ { a:2 }, { a:3 } ], j: [ 1, 2 ], k: function (a) { return a; }, l: /[az]/g, z: [ { a: undefined, b: null, c: 'b', d: 1, e: Symbol(1), f: {}, g: { b:2 }, h: { c:{ c:3 } }, i: { a:Symbol('b') }, j: { a:undefined, b:null }, k: [], l: [ 1, [ 1, 2 ], [ [ 1, 2, 3 ] ] ], m: function (a) { return !a; }, n: { a:function (a) { return !!a; } }, o: /(a|b)/i } ] }; var b = clone(a); var c = clone(a, { newFns:true }); /* Results - value beneath each for reference: aa === ba --> true undefined ab === bb --> true null ac === bc --> true 'a' ad === bd --> true 0 ae === be --> false Symbol(a) af === bf --> false {} ag === bg --> false { a:1 } ah === bh --> false [] ai === bi --> false [ { a:2 }, { a:3 } ] ai[0] === bi[0] --> false { a:2 } ai[0].a === bi[0].a --> true 2 aj === bj --> false [ 1, 2 ] ak === bk --> true ak === ck --> false function (a) { return a; } al === bl --> false /[az]/g az === bz --> false [Object] az[0].a === bz[0].a --> true undefined az[0].b === bz[0].b --> true null az[0].c === bz[0].c --> true 'b' az[0].d === bz[0].d --> true 1 az[0].e === bz[0].e --> false Symbol(1) az[0].f === bz[0].f --> false {} az[0].g === bz[0].g -- > false { b:2 } az[0].gb === bz[0].gb --> true 2 az[0].h === bz[0].h --> false { c:{ c:3 } } az[0].hc === bz[0].hc --> false { c:3 } az[0].hcc === bz[0].hcc --> true 3 az[0].i === bz[0].i --> false { a:Symbol(b) } az[0].ia === bz[0].ia --> false Symbol(b) az[0].j === bz[0].j --> false { a:undefined, b:null } az[0].ja === bz[0].ja --> true undefined az[0].k === bz[0].k --> false [] az[0].l === bz[0].l --> false [ 1, [ 1, 2 ], [ [ 1, 2, 3 ] ] ] az[0].l[1] === bz[0].l[1] --> false [ 1, 2 ] az[0].l[1][1] === bz[0].l[1][1] --> true 2 az[0].m === bz[0].m --> true az[0].m === cz[0].m --> false function (a) { return !a; } az[0].n === bz[0].n --> false { a:function (a) { return !!a; } } az[0].na === bz[0].na --> true az[0].na === cz[0].na --> false function (a) { return !!a; } az[0].o === bz[0].o --> false /(a|b)/i */