浅拷贝与深拷贝

661 阅读2分钟

1 区别

浅拷贝

  • 对于简单类型(数字、字符串、布尔),浅拷贝就是对值的拷贝
  • 对于复杂类型(对象、数组、函数),浅拷贝是对地址的拷贝,并没有开辟新的栈
  • 复杂类型拷贝的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变

深拷贝

  • 深拷贝面向的是复杂类型
  • 深拷贝会开辟新的栈,两个对象对应两个不同的地址
  • 修改一个对象的属性,不会改变另一个对象的属性
  • 真正的深拷贝一定要判断类型
  • 需要注意的是,深拷贝不会拷贝原型__proto__

2 深拷贝方法

简单深拷贝

使用Object.assign()方法
//缺点是只能深拷贝第一层属性
let a={name:'frank',child:{name:'jack'}}
let b=Object.assign({},a)
使用es6的展开运算符
//缺点是只能深拷贝第一层属性
let a={name:'frank',child:{name:'jack'}}
let b={...a}
使用concat()方法
let a=[1,2,3]
let c=[];
let b=c.concat(a);
b.push(4);
console.log(b);//1,2,3,4
console.log(a)//1,2,3
使用slice()方法
let a=[1,2,3]
let b=a.slice(0);
b.push(4);
console.log(b);//1,2,3,4
console.log(a)//1,2,3

复杂深拷贝

使用JSON的stringify和parse方法
let a={name:1,child:{name:2}}
let b=JSON.parse(JSON.stringify(a))
使用递归

递归是从底层的角度来实现深拷贝的,它是通用的

var obj = {
            arr1 : [1,2,3],
            fn: function(){
                console.log('我是一个方法')
            },
            a : '我是普通属性'
        }
        
        // 现在我要把obj字面量创建里的属性深拷贝( 属性值是引用类型也要深拷贝 )
        function deepClone(obj){
            // 根据类型制造一个新的数组或对象 => 指向一个新的空间
                // 由于数组的typeof也是'object',所以用Array.isArray(obj)
            var new_obj = Array.isArray(obj) ? [] : {};
            // 首先判断obj的类型
                // 普通类型
            if( typeof obj != 'object' ){
                // 这里不能直接返回obj,不然就是浅拷贝的性质
                return  new_obj = obj
            }
                //引用类型
                    //数组
            if(obj instanceof Array ){
                for(i = 0; i < obj.length; i++ ){
                    new_obj[i] = obj[i];
                    if(typeof new_obj[i] == 'object'){
                        deepClone(new_obj[i])
                    }
                }
            }else{ //对象
                for (let key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        // 对象中的数组和对象
                        if (typeof obj[key] == 'object') {
                            new_obj[key] = deepClone(obj[key]); 
                        }else{//对象中没有引用类型
                            new_obj[key] = obj[key]
                        }  
                    }
                }
            }
            return new_obj;
        }
        var deepClone = deepClone(obj);
        console.log(deepClone);
        // 测试是不是深拷贝
        obj.fn = '我改变了方法属性';
        console.log(obj); //{arr1: Array(3), fn: ƒ, a: "我是普通属性", c: "我新增了一个属性"}
        console.log(deepClone); // 还是 {arr1: Array(3), fn: ƒ, a: "我是普通属性"}
通过jQuery的extend方法实现深拷贝
let array = [1,2,3,4]
let newArray = $.extend(true,[],array);