概念深拷贝:将对象从内存中完整的拷贝一份出来,在堆中开辟一片新的区域存放新对象。 浅拷贝:创建一个新对象,这个对象有原始对象的一份精确拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值;如果拷贝的是内存地址,拷贝的就是它的引用。

区别:深拷贝修改新对象不会影响原对象,它们之间互不影响;浅拷贝基本数据类型之间互不影响,引用数据类型其中一个改变了内存地址,就会影响另一个对象。

浅拷贝代码实现:

1.先看基本数据类型的浅拷贝

    // 数字类型 Number
    a = 1
    b = a
    b = 2
    console.log(a, b); //1,2

    // 字符串 String
    a = 'lmx'
    b = a
    b = 'oo'
    console.log(a, b); //lmx oo

    // 布尔值 Boolean
    a=false
    b=a
    b=true
    console.log(a,b); //false,true

    // 未定义 undefined
    a = undefined
    b = a
    b = false
    console.log(a, b) //undefined false

    // 空 Null
    a = null
    b = a
    b = undefined
    console.log(a, b) //null undefined

由此得知:基本数据类型之间互不影响

2.复杂数据类型的浅拷贝

  // 对象{}
    a={ name:'abc' }
    b=a
    b.name='def'
    console.log(a,b); // def,def 
    
    // 数组[]
    a = ['a', 'b', 'c', 'd', 'e', 'f']
    b = a
    b[1] = 'd'
    console.log(a, b);// ['a', 'd', 'c', 'd', 'e', 'f']
    
    // Object.assign() 实现
    let arr = [1, 2, 3, 4, 5, 6]
    let newArr = Object.assign([], arr)
    console.log(arr); // [1, 2, 3, 4, 5, 6]
    console.log(newArr); // [1, 2, 3, 4, 5, 6]
    
    // for in
     var obj = {
        name: '小猫',
        age: 2,
        hobby: {
            eat: 'fish',
            play: 'mouse'
        }
    }
    function cat(obj) {
        let newCat = {}
        // for in 遍历属性
        for (let key in obj) {
        // hasOwnProperty:判断属性是不是自己的 返回布尔值
            if (obj.hasOwnProperty(key)) {
                newCat[key] = obj[key]
            }
        }
        return newCat
    }
    let cats = cat(obj)
    console.log(cats); //{name: '小猫', age: 2, hobby: {eat: 'fish',play: 'mouse'}}


    // 扩展运算符
    let obj = {
        name: '胖墩~',
        hobby: {
            eat: 'rice',
            look: 'me'
        }
    }
    let newObj = {
        ...obj
    }
    Object.assign(obj, newObj)
    newObj.hobby.look = '天空'
    console.log(obj);
    console.log(newObj);

    // 当类型为function Date RegExp时 a保持不变
    // 函数 function
    a = function () {
        alert('aaa')
    }
    b = a
    b = function () {
        alert('bbb')
    }
    console.log(a.toString(), b.toString()); // function () {alert('aaa')} function (){alert('bbb')}

    // 日期 Date
    a = new Date('2022/10/4 00:00:00')
    b = a
    b = new Date('2002/12/05 00:00:00')
    console.log(a, b); // Tue Oct 04 2022 00:00:00 GMT+0800 (中国标准时间) Thu Dec 05 2002 00:00:00 GMT+0800 (中国标准时间)

    // 正则 RegExp
    a = new RegExp('abc')
    b = a
    b = new RegExp('aaa')
    console.log(a, b); // /abc/ /aaa/


由此得知:当这个对象的属性是引用类型时,修改其中一个对象,另一个对象也会跟着改变,这种拷贝就是浅拷贝

深拷贝代码实现:

为什么使用深拷贝?
就是希望在改变新数组/对象的时候不影响原数组/对象

1.基本数据类型的深拷贝

// 1.
    var a = 3
    var b = a
    b = 5
    console.log(a); // 3
    console.log(b); // 5

    // 2.
    var str='细狗'
    var str1=str
    str1='粗狗'
    console.log(str); // 细狗
    console.log(str1); // 粗狗

2.复杂数据类型的深拷贝

    // JSON.parse(JSON.stringify(arr)) 这个方法无法转化 function 和 undefined
    var arr = ['lmx', true, 0, [1, 2], { age: 18 }]
    var newArr = JSON.parse(JSON.stringify(arr))
    newArr[3][0] = 100
    console.log(arr); //['lmx', true, 0, [1,2], {age:18}]
    console.log(newArr); //['lmx', true, 0, [100,2], {age:18}]
    
    // Object.assign 对象中没有嵌套对象时,才可以实现深拷贝 
    const foo = {
      name: '张三',
      age: 24
    }
    const newFoo = Object.assign({}, foo)
    foo.age = 25
    console.log(foo, newFoo) // {name: '张三', age: 25} {name: '张三', age: 24}
   
   // structuredClone
   const foo = {
    name: '张三',
    info: {
        age: 24
        }
    }
    const newFoo = structuredClone(foo) // 
    foo.info.age = 25
    console.log(foo, newFoo) // { name: '张三', info: { age: 25 }} { name: '张三', info: { age: 24 }}

   // 扩展运算符
   let a = {
        x: 1,
        y: 2
    }
    let b = {
        ...a
    }
    b.y = 3
    console.log(a.y) // 2
    console.log(b.y);// 3
    
   // 递归
   function deepClone(obj) {
	// 数据类型为引用数据类型
	if (typeof obj === 'object') {
		// 初始化返回结果
		let result = Array.isArray(obj)? []: {};
		for (let key in obj) {
			// 避免相互引用出现死循环导致爆栈
			if (obj === obj[key]) {
				continue
			}
			if (obj.hasOwnProperty(key)) {
				// 递归调用
				result[key] = deepClone(obj[key])
			}
		}
		return result;
	 } else {
	 // 基本数据类型,直接返回
		return obj
	 }
   }