请教个问题:
这句代码:var newObject = JSON.parse(JSON.stringify(oldObject));
可以简单的实现深复制,但是有几个点我不明白,
首先:JSON.stringify() 方法可以将任意的 JavaScript 值序列化成 JSON 字符串,
也就是可以把传入的数组,object对象等序列化成JSON字符串,
然后:JSON.parse() 方法可以将一个 JSON 字符串解析成为一个 JavaScript 值。
在解析过程中还可以选择性的篡改某些属性的原始解析值,也就是把刚序列化成JSON字符串的又在解析成一次并赋给newObject
不明白的是这其中的过程是怎么实现深复制了?
我了解的浅复制是两个对象都指向同一块内存地址,当修改a时,b也会自动发生变化。
而深复制是重新开辟出一块内存地址,在实现深复制后,会把a对象的各个属性全部复制到新的内存地址中,对于引用类型的变量,需要用递归来使对象的所有属性都被复制到,此后a与b没有关联了,修改a但是b不会改变
可是用JSON.parse(JSON.stringify(oldObject))
这个方法实现深复制的过程还是看不懂,麻烦解释下可以吗?
下面是测试的代码:
function cloneObject(src) {
var clone = JSON.parse(JSON.stringify(src));
return clone;
}
// 测试用例:
var srcObj = {
a: 1,
b: {
b1: ["hello", "hi"],
b2: "JavaScript"
}
};
var abObj = srcObj;
var tarObj = cloneObject(srcObj);
srcObj.a = 2;
srcObj.b.b1[0] = "Hello";
//浅复制
console.log(abObj.a); //2
console.log(abObj.b.b1[0]); //hello
//深复制
console.log(tarObj.a); // 1
console.log(tarObj.b.b1[0]); // "hello"
console.log(tarObj.b.b1[1]); //'hi'
console.log( typeof(tarObj.a) ); //Number
另外,对这句代码SF上的评论:
上面这种方法好处是非常简单易用,但是坏处也显而易见,这会抛弃对象的constructor,也就是深复制之后,无论这个对象原本的构造函数是什么,在深复制之后都会变成Object。另外诸如RegExp对象是无法通过这种方式深复制的。@jerryzou
对显而易见的坏处,还是看不明白 =_=!! 可以详细解释下吗?
然后,在GitHub上看到的实现深复制的代码:
function cloneObject(src) {
var clone = src;
// 对于Date,String,Boolean等引用类型的数据,需要考虑调用构造函数重新构造,
//直接赋值依然会有引用问题(不是真正的clone引用变量)
// 对于 Date
if (src instanceof Date) {
clone = new Date(src.getDate());
return clone;
}
// 对于Object和Array的遍历,可以使用for in,
//这样可以保证在在Array对象上扩展的属性也可以正确复制
// 对于 数组
if (src instanceof Array) {
clone = [];
for (var key in src) {
clone[key] = cloneObject(src[key]);
}
return clone;
}
// 对于 Object
if (src instanceof Object) {
clone = {};
for (var key in src) {
if (src.hasOwnProperty(key)) { // 忽略掉继承属性
clone[key] = cloneObject(src[key]);
}
}
return clone;
}
// 对于 数字 字符串 布尔 null undefined
return src;
}
我个人觉得比较完善,不过对使用 hasOwnProperty() 方法,排除继承的属性。这是为什么?
var newObject = JSON.parse(JSON.stringify(oldObject));