前端浅拷贝和深拷贝问题

前端浅拷贝与深拷贝的问题

前端的七大数据类型

	基础数据类型:  String字符串类型
				  Number 数值类型
				  Null 
				  undefined
				  Boolean 布尔类型
				  Symbol
				  
	引用数据类型:  Object
原始数据之间的拷贝都是深拷贝
其当原始数据进行赋值的时候,是将自身完全拷贝一份赋值到新的变量上
当新的变量改变后,不会对原始变量产生影响
		let a = Symbol('a');
        let b = a;
        b = Symbol('b')

        console.log('a==>', a);//a==> Symbol(a)
        console.log('b==>', b);//b==> Symbol(b)

        let c = 10;
        let d = c;
        c = 20
        console.log('c==>', c);//c==> 20
        console.log('d==>', d);//d==> 10

        let e = 'Hello world!';
        let f = e;
        f = 'I am a good man';
        console.log("e ==>", e);//e ==> Hello world!
        console.log("f ==>", f);//f ==> I am a good man
引用类型数据的拷贝就不一样了,
因为 引用类型数据直接赋值给变量的话,它只是把一个引用地址复制过去了,
这样当变量发生改变时,复制的变量和原始变量会同时改变
	    let arr = [5, 8];
        let arr1 = arr;
        arr1[0] = 3;
        // arr[0] = 3;
         /*
         这里不管是修改原copy变量,还是copy后的变量,结果都是一样,两个变量都指向同一个堆内存,修改一方必定影响另一方
        */
        console.log('arr ==>', arr); // [3,8]
        console.log('arr1 ==>', arr1);// [3,8]
       
       let obj = { name: '小红' };
       let obj1 = obj;
        obj1.age = 18;
        console.log('obj ==>', obj);//obj ==> {name: "小红", age: 18}
        console.log('obj1 ==>', obj1);//obj1 ==> {name: "小红", age: 18}
上面的就称为浅拷贝,它只是单纯的拷贝一个引用地址,
深拷贝需要分离两个引用,达到互不影响的效果

数组的分离

		//方法1
	    let array = [1, 2, 3, 4, 5];
        let array1 = array.concat();
        array1[0] = 9;
        console.log('array==>', array) //[1, 2, 3, 4, 5]
        console.log('array1==>', array1) // [9, 2, 3, 4, 5]
		
		/*
		将concat改成slice也可以有相同效果
		es6 ==> array1 = [...array] 一样效果
		原理是利用这两个数组方法会返回一个新的数组,达到分离的效果
		缺点:这两种方法都只适用于一层嵌套,在数组嵌套数组后不能达到效果[1, 2, 3, 4, [5,6]],改变5或者6,都会改变
		
		*/
		//方法2
		let array = [1, 2, 3, 4, [5, 6]];
        let array1 = JSON.parse(JSON.stringify(array));
        array1[4][0] = 9;
        console.log('array==>', array)
        console.log('array1==>', array1)
        //利用JSON.stringify将数组变成JSON字符串,再转回来,能解决多重嵌套问题

对象的分离

	    let object = { person: '小孩', age: 18 };
        let object1 = Object.assign({}, object);
        object1.book = "javascript";
        console.log("object==>", object)
        console.log("object1==>", object1)
        /*与上面数组方法一样
        es6 ==>  object1 = {...object}
        Object.assign也是返回一个新的合并对象,但是也是只能一层,对于多层嵌套的不行
*/
		//方法2
		 let object = { person: '小孩', age: 18, book: ['java', 'c++'] };
        let object1 = JSON.parse(JSON.stringify(object));
        object1.book[0] = "javascript";

        console.log("object==>", object)
        console.log("object1==>", object1)
        //利用JSON.stringify将数组变成JSON字符串,再转回来,能解决多重嵌套问题

在这里插入图片描述

使用递归遍历,进行深复制

JSON.parse(JSON.stringify(object));
按道理上面这个方法能解决一大部分的深拷贝问题,
但是对象中含有函数时,这个方法就无能为力了
let object = {
            person: '小孩', age: 18, book: ['java', 'c++'], 
            fn: function () {
                console.log('我是一个函数');
            }
        };
console.log(JSON.stringify(object)) //{"person":"小孩","age":18,"book":["java","c++"]}
/*
	很明显,当对象中含有函数时候,JSON.stringify会直接把函数去掉
*/
	//前置知识
	// 判断一个元素是什么类型
        console.log(Object.prototype.toString.call('ABC'));//[object String]
        console.log(Object.prototype.toString.call(10));//[object Number]
        console.log(Object.prototype.toString.call([1, 3, 8]));//[object Array]
        console.log(Object.prototype.toString.call({ name: '小红' }));//[object Object]

	// 封装一个判断元素类型的函数
        function typeOfEle(ele) {
            return Object.prototype.toString.call(ele).slice(8, -1);
        }
    // 迭代深拷贝函数
        function deepCopy(origin) {
            // 这是一个拦截层,当数据迭代到不是对象或数组时返回
            if ((typeOfEle(origin) != "Object") && (typeOfEle(origin) != "Array")) {
                return origin;
            }

            let target = null; //copy复制的数据类型不定
            if ((typeOfEle(origin) == "Object")) {
                // 如果拷贝的数据类型是对象
                target = {};
            } else {
                // 不然拷贝的数据类型就是数组了
                target = [];
            }
            // 遍历原始的数据
            for (let key in origin) {
                // 当遍历的数据不是对象或者数组时候,进行拷贝
                if (typeOfEle(origin[key]) != "Object" && (typeOfEle(origin[key]) != "Array")) {
                    target[key] = origin[key];
                    // 当遍历的数据是对象或者数组的时候,进行迭代再拷贝
                } else {
                    target[key] = deepCopy(origin[key]);
                }
            }
            return target;
        }
//==========================demo================
		 let object = {
            person: '小孩', age: 18, book: ['java', 'c++'], fn: function () {
                console.log('我是一个函数');
            },
            demo: {
                f1() {
                    return "我是f1";
                },
                f2() {
                    return "我是f2";
                }
            }
        };
        let object1 = deepCopy(object);
        object1.book[0] = 'javascript';
        object1.demo.f1 = function () {
            return "我是新的f1";
        }
        console.log("object==>", object)
        console.log("object1==>", object1)
        console.log("object.demo.f1==>", object.demo.f1())
        console.log("object1.demo.f1==>", object1.demo.f1())
	
	

demo结果图
在这里插入图片描述
在这里插入图片描述

总结

使用迭代遍历进行深拷贝基本能解决深拷贝问题,但是迭代本身具有性能问题
请根据具体需要使用(本人能力有限,这里挖个坑,以后有好的解决方案继续更新)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值