什么是最有效的方式来克隆一个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对象?
其他回答
function clone(obj)
{ var clone = {};
clone.prototype = obj.prototype;
for (property in obj) clone[property] = obj[property];
return clone;
}
Lodash 有一个可爱的 _.cloneDeep(值) 方法:
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
我迟到回答这个问题,但我有另一种方式来克隆对象:
function cloneObject(obj) {
if (obj === null || typeof(obj) !== 'object')
return obj;
var temp = obj.constructor(); // changed
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
obj['isActiveClone'] = null;
temp[key] = cloneObject(obj[key]);
delete obj['isActiveClone'];
}
}
return temp;
}
var b = cloneObject({"a":1,"b":2}); // calling
更快、更快的是:
var a = {"a":1,"b":2};
var b = JSON.parse(JSON.stringify(a));
和
var a = {"a":1,"b":2};
// Deep copy
var newObject = jQuery.extend(true, {}, a);
我已经标记了代码,你可以在这里测试结果:
和分享结果: 参考: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
对于想要使用 JSON.parse(JSON.stringify(obj)) 版本的人,但没有失去日期对象,您可以使用 Parse 方法的第二个论点将行转换为日期:
function clone(obj) { var regExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/; return JSON.parse(JSON.stringify(obj), function(k, v) { if (typeof v === 'string' && regExp.test(v)) return new Date(v) return v; }) } // usage: var original = { a: [1, null, undefined, 0, {a:null}, new Date()], b: { c(){ return 0 } } } var cloned = clone(original) console.log(cloned)
我的场景略有不同,我有一個物體,擁有<unk>的物體以及功能,因此,Object.assign() 和 JSON.stringify() 並沒有解決我的問題。
因此,我决定做一个简单的功能,使用内置的方法来复制一个对象,其字面特性,其粘着的对象和功能。
let deepCopy = (target, source) => {
Object.assign(target, source);
// check if there's any nested objects
Object.keys(source).forEach((prop) => {
/**
* assign function copies functions and
* literals (int, strings, etc...)
* except for objects and arrays, so:
*/
if (typeof(source[prop]) === 'object') {
// check if the item is, in fact, an array
if (Array.isArray(source[prop])) {
// clear the copied referenece of nested array
target[prop] = Array();
// iterate array's item and copy over
source[prop].forEach((item, index) => {
// array's items could be objects too!
if (typeof(item) === 'object') {
// clear the copied referenece of nested objects
target[prop][index] = Object();
// and re do the process for nested objects
deepCopy(target[prop][index], item);
} else {
target[prop].push(item);
}
});
// otherwise, treat it as an object
} else {
// clear the copied referenece of nested objects
target[prop] = Object();
// and re do the process for nested objects
deepCopy(target[prop], source[prop]);
}
}
});
};
下面是测试代码:
let a = {
name: 'Human',
func: () => {
console.log('Hi!');
},
prop: {
age: 21,
info: {
hasShirt: true,
hasHat: false
}
},
mark: [89, 92, { exam: [1, 2, 3] }]
};
let b = Object();
deepCopy(b, a);
a.name = 'Alien';
a.func = () => { console.log('Wassup!'); };
a.prop.age = 1024;
a.prop.info.hasShirt = false;
a.mark[0] = 87;
a.mark[1] = 91;
a.mark[2].exam = [4, 5, 6];
console.log(a); // updated props
console.log(b);
对于效率相关的担忧,我认为这是我遇到的问题的最简单和最有效的解决方案,我会欣赏任何关于这个算法的评论,这可能会使它更有效。
推荐文章
- 我可以在JavaScript中获得当前运行函数的名称吗?
- 如何防止输入键提交网页表单?
- 在html文本框中设置键盘插入符号的位置
- 使用jQuery选择多个类
- Cypress:只运行一个测试
- 如何同步确定JavaScript Promise的状态?
- 在Link react-router中传递道具
- 我如何承诺本地XHR?
- 如何在iframe上设置“x帧选项”?
- js比较数组
- AngularJS路由不带散列“#”
- Node.js创建文件夹或使用现有的
- 使用src动态添加脚本标签,可能包括document.write
- 单击表单中的按钮会刷新页面
- 如何创建一个jQuery函数(一个新的jQuery方法或插件)?