javascript - 这句代码是怎么实现深拷贝的?

查看:93
本文介绍了javascript - 这句代码是怎么实现深拷贝的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

请教个问题:
这句代码: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));

var a = JSON.stringify(oldObject)  
// a是一个oldObject序列化后得到的字符串 和 oldObject没任何关系的新对象
var b = JSON.parse(a); 
// b 是从字符串a反序列化为一个全新的对象 所以 不但和a没关系 和oldObject更没关系

这篇关于javascript - 这句代码是怎么实现深拷贝的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆