JS,聊聊深浅拷贝

这是我参与更文挑战的第18天,活动详情查看: 更文挑战

前言

深拷贝与浅拷贝在前端项目开发过程中,使用频率、实用性都很高的一个小工具函数了。

针对不同的业务场景,可以选择的写法也有不少。

简单的可以直接写个浅拷贝, 复杂的又根据不同的参数,处理方法也会不一样。

所以简单的讲讲深浅拷贝吧。

前置知识

不过,在写深浅拷贝之前,我们是不是得先知道下,为什么要写深浅拷贝呢?直接赋值拷贝不行吗?

为什么要写?

在JavaScript中, 有两大类数据类型:基本类型、引用类型。

基本类型:常见的如数字、字符串、布尔值等都属于基本类型,这类数据类型在内存中占据固定大小,保存在栈内存中。

引用类型:我们常用的数组、对象都属于引用类型,保存在堆内存中,而堆内存中存储的是目标的存储地址。

两种类型的区别在于:

如果一个变量存储的基本类型,那么将该变量赋值给另一个变量时,执行的复制操作。

如果是引用类型,那么该变量与被赋值的变量,操作的是同一个数组、对象。

看个例子:

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

var arr1 = [1,2,3];
var arr2 = arr1;
arr1.push(4);
console.log(arr1);  // [1,2,3,4]
console.log(arr2);  // [1,2,3,4]
复制代码

可以看到,基本类型赋值之后,互不影响。 而引用类型则是貌离神合

在实际业务开发中,如果需要复制一份引用类型的数据的话,操作数据会影响另一个变量可就太容易出事了。

所以,就回答了前面的问题,为什么要写深浅拷贝。

浅拷贝

前面已经聊完了为什么要写拷贝工具函数,那么这里就进入正文,先看看浅拷贝的几种方式;

1、数组:Array.slice() 针对数组的浅拷贝

let a = [1,2,3,4]
let b = a.slice();

a.push(5);
console.log(a); // -> [1, 2, 3, 4, 5]
console.log(b); // -> [1, 2, 3, 4]
复制代码

2、数组:Array.concat()

let a = [1,2,3,4]
let b = a.concat();

a.push(5);
console.log(a); // -> [1, 2, 3, 4, 5]
console.log(b); // -> [1, 2, 3, 4]
复制代码

3、对象:Object.assign() 对象浅拷贝

let obj = {name: 'Corey'}
let obj2 = {};

Object.assign(obj2, obj); // 对象obj的值会覆盖obj2中重复的值;obj2中没有,则新增进去。
obj.age = 18;
console.log(obj);   // {name: 'Corey', age: 18}
console.log(obj2);  // {name: 'Corey'}

// 简写
let obj2 = Object.assign({}, obj);
复制代码

深拷贝

浅拷贝应对的情况比较单一,但是如果通过函数结合起来,自动判断数据类型,并响应的执行拷贝是不是就会强大起来呢?

这里介绍两种写法。

1、数组、对象混合的情况

主要借助JS的函数,JSON.parse() 解析json, 以及JSON.stringify()转JSON函数;

将元数据转为字符串,再重新解析为可操作性的数据,就将数据复制出来一份了,并且不会改变元数据。

let data = [
    1,2,3
    {name: 'corey', age: 12}
]
let dataCopy = JSON.parse(JSON.stringify(data));
复制代码

2、手动实现一个深拷贝

前面的写法过于简单粗暴了?那这里就手动实现一个吧? 为什么有简单的,还要自己折腾一个呢?

为了耍帅?NoNoNo,当然不是, 在JS中,还有很多其他类型,例如函数Function,函数是无法通过上面的方式直接实现拷贝的, 所以手动实现虽然相对麻烦一些,但是更灵活。

let obj = {
    name: 'name',
    age: 23,
    info: {
        desc: 'hello'
    },
    color: ['red','green','blue']
};
let obj2 = {};

function deepClone(res, source){
    for(let key in source){
	let item = res[key];
        if(item instanceof Array){
            res[key] = [];
            deepClone(obj[key], item)
        } else if(item instanceof Object){
            res[key] = {};
            deepClone(res[key], item);
        } else {
            res[key] = item;
        }
    }
}

deepClone(obj2, obj);
复制代码

总结

太困了太困了, 今天就写到这里。

希望能帮助到各位小伙伴。

有什么疑问、或者想要讨论的都可以在评论区留言讨论哦。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享