JavaScript中的克隆对象
这个问题在这里已经有了答案:
这将不会被引用
<script>
var obj =
{
name: 'abc',
age: '30'
};
var objTwo = {};
for( var i in obj )
{
objTwo[i] = obj[i];
}
</script>
查看小提琴
我会用jQuery来做到这一点:
var obj1 = {
name: "abc",
age: 20
}
console.log(obj1);
var obj2 = $.extend({}, obj1, {});
console.log(obj2);
obj2.age = 1;
console.log(obj2);
console.log(obj1);
如果你只需要克隆简单的对象,简单地做
JSON.parse (JSON.stringify (obj))
就足够了。
但是,这显然不适用于所有情况,因为JSON.stringify
无法处理循环引用并删除函数。
所以如果你想超越这个范围,事情会变得更加复杂,你必须依靠一些实用程序库或需要实现自己的深度克隆方法。
这是一个预计要进行克隆的深度级别的示例实现。
(function (Object, Array) {
function cloneObject(deep, scope, clonedScope) {
var type = typeof this,
clone = {},
isCR = -1;
deep = Number(deep) || 0;
scope = scope || [];
clonedScope = clonedScope || [];
if (!Array.isArray(scope) || !Array.isArray(clonedScope) || clonedScope.length !== scope.length) {
throw new TypeError("Unexpected input");
}
//If we find a primitive, we reeturn its value.
if (type !== "object") {
return this.valueOf();
}
scope.push(this);
clonedScope.push(clone);
if (0 === deep) { //If we reached the recursion limit, we can perform a shallow copy
for (var prop in this) {
clone[prop] = this[prop];
}
} else { //Otherwise we need to make some checks first.
for (var prop in this) {
if ((isCR = scope.indexOf(this[prop])) > -1) { //If we find a circular reference, we want create a new circular reference to the cloned version.
clone[prop] = clonedScope[isCR];
} else if (typeof this[prop] !== "undefined" && this[prop] !== null) { //Otherwise continue cloning.
clone[prop] = (typeof this[prop] !== "object" ? this[prop] : this[prop].clone(deep - 1, scope, clonedScope)); //If we find a non object, we can directly assign it. Otherwise we need to recursively call the clone function, counting down the limit, and injecting the scopeArrays, to find circular references.
} else { //If the property is undefined or null, assign it as such.
clone[prop] = this[prop];
}
}
}
scope.pop(); //If we leave a recursion leve, we remove the current object from the list.
clonedScope.pop();
return clone;
}
function cloneArray(deep, scope, clonedScope) {
var clone = [];
deep = Number(deep) || 0;
scope = scope || [];
clonedScope = clonedScope || [];
if (!Array.isArray(scope) || !Array.isArray(clonedScope) || clonedScope.length !== scope.length) {
throw new TypeError("Unexpected input");
}
scope.push(this);
clonedScope.push(this);
if (0 === deep) clone = this.concat();
else this.forEach(function (e) {
if ((isCR = scope.indexOf(e)) > -1) {
clone.push(clonedScope[isCR]);
} else if (typeof e !== "undefined" && e !== null) {
clone.push((typeof e !== "object" ? e : e.clone(deep - 1, scope, clonedScope)));
} else {
clone.push(e);
}
});
scope.pop();
clonedScope.pop();
return clone;
}
Object.defineProperty(Object.prototype, "clone", {
enumerable: false,
value: cloneObject
});
Object.defineProperty(Array.prototype, "clone", {
enumerable: false,
value: cloneArray
});
})(Object, Array);
请注意,扩展内置原型通常是不被接受的,但是我决定这样做,以避免额外的类型检查,并将数组和对象的逻辑分开多一点。 这可以轻松地重构为普通函数
一些测试来检查我们确实有新的参考。
var first = {
a: {
b: "b",
c: {
}
},
b: "asd",
c: [{}],
d: undefined,
e: null,
f: function a() {} //functions keep their original reference..
};
first.a.c.a = first.a; //Circular object reference
first.c.push(first.c); //Circular array reference
var second = first.clone(Infinity);
console.log(second, second.a === second.a.c.a, first.a !== second.a.c.a); //..., true, true.
可能还有很多需要改进的空间,我特别不喜欢范围和cloneScope被注入的方式。 如果任何人有更好的想法找到并重新连接循环引用,我很乐意更新答案
这也是一个小提琴。
链接地址: http://www.djcxy.com/p/24763.html