浅拷贝和深拷贝的区别

一、数据类型

在讨论深浅拷贝之前,我们先说说数据类型,因为深浅拷贝与数据类型有关。

数据类型分为基本数据类型(String、Number、Boolean、Null、Undefined、Symbol (es6引入的一种类型) )和引用数据类型(Object、Array、Function)。

基本数据类型特点:直接存储在栈中;

引用数据类型:它真实的数据是存储在堆内存中,栈中存储的只是指针,指向在堆中的实体地址。

二、浅拷贝、深拷贝

深浅拷贝只是针对Array与Object这样的引用数据类型。简单来说,浅拷贝只是拷贝了它在栈中存储的指针,它们指向的都是同一个堆内存地址,所以浅拷贝在某些情况会造成改变数据后导致别的另一份数据也同步被改变的情况;而深拷贝是直接将堆内存中存储的数据直接复制一份,不会有浅拷贝互相影响的问题。

三、浅拷贝的方法

1. Object.assign()

 

 

 

 从上面的例子我们发现,用Object.assign()实现的浅拷贝,当拷贝对象中的字段第一层的值为基础数据类型(如上面的a的值是个字符串,“a1”),那是不会被同步影响的;如果第一层的值还包含子对象(如上面b的值就是个对象,还包含了name字段),那就会被影响。所以如果被复制的object的每个字段第一层都是基础数据类型,那就是深拷贝。

2. Array.prototype.concat()

3. Array.prototype.slice()

2和3的方式效果与1一样,都是第一层的值为基础数据类型不会被同步影响,否则就会。

四、深拷贝的方法

1. JSON.parse(JSON.stringify())

将一个对象先转为json字符串,然后再转回来,这样可以实现深拷贝。

但是这个方法有个缺陷,可以实现对象或数组的深拷贝,但是不能处理函数,函数经过这样处理后会变成null。

 

 

 

 

 

所以比较推荐的方法是:

1. 递归的方法,遍历要克隆的每个字段,发现它的值是对象或数组后继续递归。

复制代码
function clone(target) {
    let res = undefined;
    if (Object.prototype.toString.call(target) === '[object Object]') {
        res = {};
    } else if (Object.prototype.toString.call(target) === '[object Array]') {
        res = [];
    } else {
        return target;
    }
    for (let key in target) {
        let value = target[key];
        if (Object.prototype.toString.call(value) === '[object Object]' || Object.prototype.toString.call(value) === '[object Array]') {
            res[key] = clone(value);
        } else {
            res[key] = value;
        }
    }
    return res;
}
let a = [1,2,3,{ a: "a1", b: { name: "张三" } }]
let b = clone(a)
b[3].b.name = "我是b"
console.log(a,b)
复制代码

 

 

 

2. 比较推荐的方法,引用lodash依赖,使用里面的cloneDeep()方法

posted on 2024-07-09 14:16  itjeff  阅读(2)  评论(0编辑  收藏  举报

导航