JavaScript知识点回顾(二十四)——复制对象

257 阅读2分钟

这是我参与8月更文挑战的第二十四天,活动详情查看:8月更文挑战

复制对象

JavaScript初学者最常见的一个问题就是如何复制一个对象。看起来应该有一个内置的copy()方法。然而事情并没有想象的那么简单,因为无法选择一个默认的复制算法。 比如:

    function anotherFunction(){
        console.log("juejin");
    }
    var anotherObject = {
        c:true
    };
    var anotherArray = [1,2];
    var myObject = {
        a:2,
        b:anotherObject,
        c:anotherArray,
        d:anotherFunction
    };
    anotherArray.push(anotherObject,myObject);

如果要准确的表示myObject的复制,首先要判断它到底是浅拷贝还是深拷贝。对于浅拷贝来说,复制出来的新对象中a的值会复制旧对象中a的值,也就是2。但是新对象中b、c、d三个属性其实只是三个引用罢了,它们和旧对象中b、c、d的引用的对象是一样的。而对于深拷贝来说,除了复制myObject以外还会复制anotherObject和anotherArray。这个时候就出问题了,anotherArray引用了anotherObject和myObject,所以又需要复制myObject,这样就会由于循环引用而导致死循环,俗称套娃。那是否应该检测这种套娃并终止循环?还是直接报错?

除了套娃的问题以外,我们还不确定“复制”一个函数意味着什么。有些人会通过toString()来序列化一个函数的源代码,但是这种操作的结果完全取决于JavaScript的具体实现,而且不同的引擎对于不同类型的函数处理方式并不完全相同。

对于json安全的对象来说有一种巧妙的办法: (ps:json安全指可以被序列化为一个JSON字符串并且可以根据这个字符串解析出一个结构和值完全一样的对象)

    var newObj = JSON.parse(JSON.stringify(someObj));

不过这种方法必须确保对象是JSON安全的,所以只适用于部分的情况。

而相比于深拷贝,浅拷贝就很易懂并且问题也少很多了,所以ES6定义了Object.assign()方法来实现浅拷贝。Object.assign()方法的第一个参数是一个目标对象,之后还可以跟一个或者多个源对象。它会便利所有源对象中的可枚举的自由键,并把它们复制(使用=操作符进行赋值)到目标对象,最后返回目标对象。