什么是最有效的方式来克隆一个JavaScript对象?我已经看到obj = eval(uneval(o));被使用,但它是非标准的,仅支持Firefox.我做了事情,如obj = JSON.parse(JSON.stringify(o));但质疑效率。
当前回答
这是我创建的最快的方法,不使用原型,所以它将保持在新对象中拥有自己的所有权。
解决方案是对原件的顶级属性进行 iterate,创建两个副本,从原件中删除每个属性,然后重新设置原件并返回新副本,它只需要像顶级属性一样多次 iterate。
唯一的缺点是,原始对象必须配备其原创创建的名称空间,以便重新设置。
copyDeleteAndReset:function(namespace,strObjName){
var obj = namespace[strObjName],
objNew = {},objOrig = {};
for(i in obj){
if(obj.hasOwnProperty(i)){
objNew[i] = objOrig[i] = obj[i];
delete obj[i];
}
}
namespace[strObjName] = objOrig;
return objNew;
}
var namespace = {};
namespace.objOrig = {
'0':{
innerObj:{a:0,b:1,c:2}
}
}
var objNew = copyDeleteAndReset(namespace,'objOrig');
objNew['0'] = 'NEW VALUE';
console.log(objNew['0']) === 'NEW VALUE';
console.log(namespace.objOrig['0']) === innerObj:{a:0,b:1,c:2};
其他回答
在我以前的测试中,速度是我发现的主要担忧。
JSON.parse(JSON.stringify(obj))
是最慢的方式来深化一个对象(它比 jQuery.extend 更慢,深旗定为 10-20% )。
jQuery.extend 是相当快的,当深旗被设置为虚假(shallow clone)。这是一个很好的选择,因为它包含一些额外的逻辑的类型验证,并且不复制未定义的属性,等等,但这也将放缓你下一点。
如果你知道你正在试图克隆的对象的结构,或者可以避免深深的<unk>,你可以写一个简单的为(var i in obj) loop 克隆你的对象,同时检查 hasOwnProperty 它会比 jQuery 快得多。
var clonedObject = {
knownProp: obj.knownProp,
..
}
更新 ES6
Object.assign({}, obj);
如果您正在使用它,UnderScore.js图书馆有一个克隆方法。
var newObject = _.clone(oldObject);
这是一个回归的解决方案:
obj = { a: { b: { c: { d: ['1', '2'] } } }, e: 'Saeid' } const Clone = function (obj) { const container = Array.isArray(obj) ? [] : {} const keys = Object.keys(obj) for (let i = 0; i < keys.length; i++) { const key = keys[i] if(typeof obj[key] == 'object') { container[key] = Clone(obj[key]) } else container[key] = obj[key].slice() } return container } console.log(Clone(obj))
代码:
// extends 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returned
function extend(from, to)
{
if (from == null || typeof from != "object") return from;
if (from.constructor != Object && from.constructor != Array) return from;
if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function ||
from.constructor == String || from.constructor == Number || from.constructor == Boolean)
return new from.constructor(from);
to = to || new from.constructor();
for (var name in from)
{
to[name] = typeof to[name] == "undefined" ? extend(from[name], null) : to[name];
}
return to;
}
测试:
var obj =
{
date: new Date(),
func: function(q) { return 1 + q; },
num: 123,
text: "asdasd",
array: [1, "asd"],
regex: new RegExp(/aaa/i),
subobj:
{
num: 234,
text: "asdsaD"
}
}
var clone = extend(obj);
希望这能帮助。
function deepClone(obj) {
/*
* Duplicates an object
*/
var ret = null;
if (obj !== Object(obj)) { // primitive types
return obj;
}
if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) { // string objecs
ret = obj; // for ex: obj = new String("Spidergap")
} else if (obj instanceof Date) { // date
ret = new obj.constructor();
} else
ret = Object.create(obj.constructor.prototype);
var prop = null;
var allProps = Object.getOwnPropertyNames(obj); //gets non enumerables also
var props = {};
for (var i in allProps) {
prop = allProps[i];
props[prop] = false;
}
for (i in obj) {
props[i] = i;
}
//now props contain both enums and non enums
var propDescriptor = null;
var newPropVal = null; // value of the property in new object
for (i in props) {
prop = obj[i];
propDescriptor = Object.getOwnPropertyDescriptor(obj, i);
if (Array.isArray(prop)) { //not backward compatible
prop = prop.slice(); // to copy the array
} else
if (prop instanceof Date == true) {
prop = new prop.constructor();
} else
if (prop instanceof Object == true) {
if (prop instanceof Function == true) { // function
if (!Function.prototype.clone) {
Function.prototype.clone = function() {
var that = this;
var temp = function tmp() {
return that.apply(this, arguments);
};
for (var ky in this) {
temp[ky] = this[ky];
}
return temp;
}
}
prop = prop.clone();
} else // normal object
{
prop = deepClone(prop);
}
}
newPropVal = {
value: prop
};
if (propDescriptor) {
/*
* If property descriptors are there, they must be copied
*/
newPropVal.enumerable = propDescriptor.enumerable;
newPropVal.writable = propDescriptor.writable;
}
if (!ret.hasOwnProperty(i)) // when String or other predefined objects
Object.defineProperty(ret, i, newPropVal); // non enumerable
}
return ret;
}
HTTPS://github.com/jinujd/Javascript-Deep-Clone