欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

浅拷贝与深拷贝多种实现

程序员文章站 2022-04-27 08:45:45
...

浅拷贝

拷贝对象

使用for in循环实现

测试对象: obj(源), obj2(目标)
    let obj = {
            a:"1",
            b:"man",
            func:function(){
                console.log("测试");
            },
            ob:{
                ab:"第二层",
                sex:"women"
            },
            c:[],
            arr:[1,23,4,"str",{name:"数组里面的测试对象"}
        }

        let obj2 = {};
简单实现
	 for(let prop in obj){
          obj2[prop] = obj[prop];
     }

使用assign实现

	Object.assign(obj2,obj);

使用扩展运算符实现

	obj2 = {obj};

使用JSON对象拷贝

	let tmp = JSON.stringify(obj);
	obj2 = JSON.parse(tmp);

拷贝数组

使用slice或concat拷贝

测试用例 arr1(源), arr2(目标)
	 let arr1 = ["a",1,{name:"第二层",arrDeep:[1,23,5,7]}];
     let arr2 = [];
	 arr2 = arr1.slice();
     arr2 = arr1.concat();
	//结果返回的是新的引用 ,但是内容第二层会变为arr1的引用
	["a", 1, {name:"第二层",arrDeep:[1,23,5,7]}]

使用for遍历实现也行 跟对象的内容差不多

深拷贝

使用constructor判断

测试对象: obj(源), obj2(目标)
    let obj = {
            a:"1",
            b:"man",
            func:function(){
                console.log("测试");
            },
            ob:{
                ab:"第二层",
                sex:"women"
            },
            c:[],
            arr:[1,23,4,"str",{name:"数组里面的测试对象"}
        }

        let obj2 = {};
代码测试及结果
	 function  deepClone(origin){
            let target = origin.constructor === Array? []:{};//判断复制源为什么类型
            for(let prop in origin){
                if(origin.hasOwnProperty(prop)){//是否为原型链上的属性
                    if(typeof origin[prop] == "object"){//判断是否为基本数据类型
                        origin[prop].constructor === Array ?  target[prop] = []:target[prop] = {};
                        target[prop] = deepClone(origin[prop]);//为引用数据类型 深层拷贝 递归调用自身   
                    }else{
                        target[prop] = origin[prop];//正常复制
                    }
                }
            }
            return target;
        }
        obj2 = deepClone(obj);

浅拷贝与深拷贝多种实现

使用Object.prototypy.toString.call()判断

代码测试及结果
	 function  deepClone(origin){
            let toStr = Object.prototype.toString;//保存函数引用
            let arrayStr = "[object Array]"; //储存调用函数判断为数组时返回的值
            let target = toStr.call(origin) ==  arrayStr? []:{};//判断复制源为什么类型
            for(let prop in origin){
                if(origin.hasOwnProperty(prop)){//是否为原型链上的属性
                    if(typeof origin[prop] == "object"){//判断是否为基本数据类型
                        toStr.call(origin[prop]) ==  arrayStr ?  target[prop] = []:target[prop] = {};
                        target[prop] = deepClone(origin[prop]);//为引用数据类型 深层拷贝 递归调用自身   
                    }else{
                        target[prop] = origin[prop];//正常复制
                    }
                }
            }
            return target;
        }
        obj2 = deepClone(obj);

浅拷贝与深拷贝多种实现

使用Array.isArray()判断

代码测试及结果
	 function  deepClone(origin){
            let toStr = Object.prototype.toString;//保存函数引用
            let arrayStr = "[object Array]"; //储存调用函数判断为数组时返回的值
            let target = toStr.call(origin) ==  arrayStr? []:{};//判断复制源为什么类型
            for(let prop in origin){
                if(origin.hasOwnProperty(prop)){//是否为原型链上的属性
                    if(typeof origin[prop] == "object"){//判断是否为基本数据类型
                        toStr.call(origin[prop]) ==  arrayStr ?  target[prop] = []:target[prop] = {};
                        target[prop] = deepClone(origin[prop]);//为引用数据类型 深层拷贝 递归调用自身   
                    }else{
                        target[prop] = origin[prop];//正常复制
                    }
                }
            }
            return target;
        }
        obj2 = deepClone(obj);
结果

浅拷贝与深拷贝多种实现

总结

深度拷贝分为一下几步:

  • 判断复制目标为数组还是对象
  • 循环遍历属性(注意排除原型链上的属性
  • 先用typeof判断是否为基本属性
  • 若是则直接复制
  • 若不是 则使用函数判断为数组或者为对象,分别赋值并递归调用自身
相关标签: 前端