aermin / blog

📝 My blog / notes

Home Page:https://www.aermin.top/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

js浅拷贝与深拷贝(2017.09.04)

aermin opened this issue · comments

深浅拷贝区别

深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象(引用类型)的。

复制引用(引用类型)的拷贝方法称之为浅拷贝,也因为直接复制引用类型,导致新旧对象共用一块内存地址,会互相影响,具体看例子

深拷贝就是指完全的拷贝一个对象,将原对象的各个属性递归复制下来。这样即使嵌套了对象,两者也相互分离。

浅拷贝

var shallowCopy = function(obj) {
    if (typeof obj !== 'object') return;      // 只拷贝对象
    var newObj = obj instanceof Array ? [] : {};     // 根据obj的类型判断是新建一个数组还是对象
    for (var key in obj) {      // 遍历obj,并且判断是obj的属性才拷贝
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;
}

var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);
shallowObj.arr[1] = 5;
console.log(obj.arr[1])  // 5
shallowObj.a = 5;
console.log(obj.a) // 1 

备注:

①hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性。Object.prototype.hasOwnProperty(),;
②instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。换种说法就是如果左侧的对象是右侧类的实例, 则表达式返回true, 否则返回false 。

原理

遍历对象,然后把属性和属性值都放在一个新的对象

具体:判断是参数否为对象,是数组还是object;用 for in 遍历所传的参数对象,并用 if (arg.hasOwnProperty(prop)) 忽略掉继承属性,然后赋值给临时创建的对象,最后返回此对象。

深拷贝

实现一个深拷贝在拷贝的时候判断一下属性值的类型,如果是对象,我们递归调用深拷贝函数就OK了

var deepCopy = function(obj) {
    if (typeof obj !== 'object') return;
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
        }
    }
    return newObj;
}

var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);
shallowObj.arr[1] = 5;
console.log(obj.arr[1])  // 3
shallowObj.a = 5;
console.log(obj.a) // 1 

性能问题

尽管使用深拷贝会完全的克隆一个新对象,不会产生副作用,但是深拷贝因为使用递归,性能会不如浅拷贝,在开发中,还是要根据实际情况进行选择。

本文参考地址

待续:

https://www.zhihu.com/question/23031215
https://yanhaijing.com/javascript/2018/10/10/clone-deep/
https://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript
https://segmentfault.com/a/1190000002789651