深拷贝和浅拷贝

深拷贝

深拷贝是将一个对象从内存中完整的拷贝一份出来。从堆内存中开辟一个新的区域存放新的对象(新旧对象不共享同一块内存),且修改新对象不会影响到原来的对象。(深拷贝是在堆内存申请新的空间来存储数据,避免指针悬挂)

实现方式如下

复制代码
JSON.parse(JSON.stringify())

注意: 上面的方法虽然可以实现数组或对象的深拷贝,但是不能处理函数和正则,,经过上面的拷贝后得到的正则就不再是正则(变为空对象),得到的函数也不再是函数(变为null)。

递归方法实现深度克隆:遍历对象、数组直到里面是基本数据类型,然后再去复制,就是深度拷贝。

javascript 复制代码
function  deepClone(obj) {
        if (typeof obj !== 'object' || obj == null) {
            return obj
        }
        let result
        if (obj instanceof Array) {
            result = []
        } else {
            result = {}
        }
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                result[key] = deepClone(obj[key])
            }
        }
        return result
    }


    function deepClone(obj, hash = new WeakMap()) {
        if (obj === null) return obj; //如果是null或者是undefined 我就不进行拷贝操作
        if (obj instanceof Date) return new Date(obj);
        if (obj instanceof RegExp) return new RegExp(obj);  //如果可能是对象或者普通的值如果是函数的话就不需要拷贝
        if (typeof obj !== "object") return obj   //是对象的话就要深拷贝
        if (hash.get(obj)) return hash.get(obj);
        let cloneObj = new obj.constructor();
        //找到的是所属类型上的constructor,而原型上的constructor指向的是当前的类本身
        hash.set(obj, cloneObj);
        hash.set(obj, cloneObj)
        for (let key in obj) {
            if (obj.hasOwnProperty('key')) {
                cloneObj[key] = deepClone(obj[key], hash)
            }
        }
        return cloneObj
    }

浅拷贝

浅拷贝是创建一个新对象,这个对象有着原始对象的属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存的地址。所以其中一个对象改变了地址,就会影响到另一个对象。

实现方式如下

1、Object.assign(); 可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,最后返回目标对象。

javascript 复制代码
 let obj1 = {
        person: {
            name: '张三',
            age: 21
        },
        sports: 'basketball'
    }
    let obj2 = Object.assign({}, obj1)
    obj2.person.name = "艺青桑";
    obj2.sports = "football";
    console.log(obj1) // {person: {name: '艺青桑', age:21},sports: "basketball"}
    console.log(obj2); //    {person: {name: '艺青桑', age:21}, sports: 'football'}
复制代码

2、展开运算符 是es6的特性,它提供了一种非常方便的方式来进行浅拷贝,与object.assign()的功能相同

javascript 复制代码
let obj1 = { name: '文博', address: { x: 100, y: 100 } }
    let obj2 = { ...obj1 };
    obj1.address.x = 200;
    obj1.name = '嘉兴';
    console.log(obj2);//{ name: '文博', address: { x: 200, y: 100 }}
    console.log(obj1);//{ name: '嘉兴', address: { x: 200, y: 100 }}

3、Array.prototype.concat();

javascript 复制代码
 let arr=[1,3,{username:'贺丽'}]
    let arr2=arr.concat();
    arr[2].username='亚楠';
    console.log(arr)  //[1,3,{username:'亚楠'}]

4、 Array.prototype.slice()

javascript 复制代码
let arr = [1, 3, { username: '再兴' }]
    let arr3 = arr.slice();
    arr3[2].username = '艺青';
    console.log(arr) // [1,3,{username:'艺青'}]

赋值与深浅拷贝的区别

|-----|--------------------------------------------------------------------------------------------------------|--------------------------------------------------|---------------------------------------------------------|
| | 赋值 | 深拷贝 | 浅拷贝 |
| | 当我们把一个对象赋值给一个新的变量时,赋的其实是给该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论那个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。 | 从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。 | 重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。 |
| | 和原数据是否指向同一对象 | 第一层数据为基本数据类型且修改基本类型数据时 | 原数据中包含子对象且修改子对象时 |
| 赋值 | 是 | 改变会使原数据一起改变 | 改变会使原数据一起改变 |
| 深拷贝 | 否 | 改变不会使原数据一起改变 | 改变不会使原数据一起改变 |
| 浅拷贝 | 否 | 改变不会使原数据一起改变 | 改变会使原数据一起改变 |

文章中提到的栈内存和堆内存,有不懂得可以参观下面的地址

秒懂 栈内存和堆内存(深入底层)-CSDN博客

相关推荐
风清扬_jd18 分钟前
Chromium 中JavaScript Fetch API接口c++代码实现(二)
javascript·c++·chrome
丁总学Java34 分钟前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
It'sMyGo44 分钟前
Javascript数组研究09_Array.prototype[Symbol.unscopables]
开发语言·javascript·原型模式
懒羊羊大王呀1 小时前
CSS——属性值计算
前端·css
xgq1 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
李是啥也不会1 小时前
数组的概念
javascript
无咎.lsy1 小时前
vue之vuex的使用及举例
前端·javascript·vue.js
fishmemory7sec1 小时前
Electron 主进程与渲染进程、预加载preload.js
前端·javascript·electron
fishmemory7sec1 小时前
Electron 使⽤ electron-builder 打包应用
前端·javascript·electron
豆豆2 小时前
为什么用PageAdmin CMS建设网站?
服务器·开发语言·前端·php·软件构建