什么是最有效的方式来克隆一个JavaScript对象?我已经看到obj = eval(uneval(o));被使用,但它是非标准的,仅支持Firefox.我做了事情,如obj = JSON.parse(JSON.stringify(o));但质疑效率。
当前回答
function clone(obj) {
var copy;
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
使用下列方法而不是 JSON.parse(JSON.stringify(obj)) 因为它比下列方法慢。
我如何正确地克隆一个JavaScript对象?
其他回答
扩展操作器... (原始序列 - 仅) 序列(0) (原始序列 - 仅) 序列() (原始序列 - 仅) concat() (原始序列 - 仅) 定制功能,如下所示(每个序列) jQuery 的 $.extend() (每个序列) JSON.parse(JSON.stringify()) (原始和字面序列 - 仅) Underscore 的 _.clone() (原始和字面序列 - 仅) Lodash 的 _.cloneDeep() (每个序列)
let arr1a = [1, 'a', true];
let arr1b = [...arr1a];
而且在哪裡 slice() 比 concat( 有更好的性能: https://jsbench.me/x5ktn7o94d/
let arr1c = arr1a.splice(0);
let arr1d = arr1a.slice();
let arr1e = arr1a.concat();
let arr2a = [1, 'a', true, {}, []];
let arr2b = JSON.parse(JSON.stringify(arr2a));
let arr3a = [1, 'a', true, {}, [], new Object()];
function copy(aObject) {
// Prevent undefined objects
// if (!aObject) return aObject;
let bObject = Array.isArray(aObject) ? [] : {};
let value;
for (const key in aObject) {
// Prevent self-references to parent object
// if (Object.is(aObject[key], aObject)) continue;
value = aObject[key];
bObject[key] = (typeof value === "object") ? copy(value) : value;
}
return bObject;
}
let arr3b = copy(arr3a);
或使用第三方实用功能:
let arr3c = $.extend(true, [], arr3a); // jQuery Extend
let arr3d = _.cloneDeep(arr3a); // Lodash
注意: jQuery 的 $.extend 也比 JSON.parse(JSON.stringify() 表现更好):
Object.assign({},sourceObj)只有在其属性没有参考类型密钥时才会克隆对象。
obj={a:"lol",b:["yes","no","maybe"]}
clonedObj = Object.assign({},obj);
clonedObj.b.push("skip")// changes will reflected to the actual obj as well because of its reference type.
obj.b //will also console => yes,no,maybe,skip
因此,对于深度克隆,不可能以这种方式实现。
最有效的解决方案是
var obj = Json.stringify(yourSourceObj)
var cloned = Json.parse(obj);
使用今天的JavaScript来克隆一个对象:ECMAScript 2015(以前被称为ECMAScript 6)
var original = {a: 1};
// Method 1: New object with original assigned.
var copy1 = Object.assign({}, original);
// Method 2: New object with spread operator assignment.
var copy2 = {...original};
旧浏览器可能不支持 ECMAScript 2015. 一个常见的解决方案是使用 JavaScript-to-JavaScript 编译器,如 Babel 发行您的 JavaScript 代码的 ECMAScript 5 版本。
正如 @jim-hall 指出的那样,这只是一个微小的副本. 属性属性被复制为参考:更改一个将改变另一个对象/实例的值。
这通常不是最有效的解决方案,但它是我需要的。
function clone(obj, clones) {
// Makes a deep copy of 'obj'. Handles cyclic structures by
// tracking cloned obj's in the 'clones' parameter. Functions
// are included, but not cloned. Functions members are cloned.
var new_obj,
already_cloned,
t = typeof obj,
i = 0,
l,
pair;
clones = clones || [];
if (obj === null) {
return obj;
}
if (t === "object" || t === "function") {
// check to see if we've already cloned obj
for (i = 0, l = clones.length; i < l; i++) {
pair = clones[i];
if (pair[0] === obj) {
already_cloned = pair[1];
break;
}
}
if (already_cloned) {
return already_cloned;
} else {
if (t === "object") { // create new object
new_obj = new obj.constructor();
} else { // Just use functions as is
new_obj = obj;
}
clones.push([obj, new_obj]); // keep track of objects we've cloned
for (key in obj) { // clone object members
if (obj.hasOwnProperty(key)) {
new_obj[key] = clone(obj[key], clones);
}
}
}
}
return new_obj || obj;
}
自行车测试...
a = []
a.push("b", "c", a)
aa = clone(a)
aa === a //=> false
aa[2] === a //=> false
aa[2] === a[2] //=> false
aa[2] === aa //=> true
功能测试...
f = new Function
f.a = a
ff = clone(f)
ff === f //=> true
ff.a === a //=> false
这是我的解决方案,没有使用任何图书馆或本地JavaScript功能。
function deepClone(obj) {
if (typeof obj !== "object") {
return obj;
} else {
let newObj =
typeof obj === "object" && obj.length !== undefined ? [] : {};
for (let key in obj) {
if (key) {
newObj[key] = deepClone(obj[key]);
}
}
return newObj;
}
}