深浅拷贝
灵感胜于汗水 Lv5

赋值

赋值是将某一数值或对象赋给某个变量的过程,分为下面 2 部分

  • 基本数据类型:赋值,赋值之后两个变量互不影响
  • 引用数据类型:赋,两个变量具有相同的引用,指向同一个对象,相互之间有影响

浅拷贝

创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

简单实现一个浅拷贝:

1
2
3
4
5
6
7
8
9
function shallowClone(obj) {
const newObj = {};
for(let prop in obj) {
if(obj.hasOwnProperty(prop)){
newObj[prop] = obj[prop];
}
}
return newObj;
}

JavaScript中,存在浅拷贝的现象有:

  • Object.assign:用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
  • Array.prototype.slice():方法返回一个新的数组对象,这一对象是一个由 beginend(不包括end)决定的原数组的浅拷贝
  • Array.prototype.concat():用于合并两个或多个数组。不会更改现有数组,而是返回一个新数组。
  • 使用拓展运算符(…)实现的复制

深拷贝

深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。

常见的深拷贝方式有:

  • JSON.parse(JSON.stringify(object))

    但是该方法有以下几个问题:

    1、会忽略 undefined

    2、会忽略 symbol

    3、不能序列化函数

    4、不能解决循环引用的对象

    5、不能正确处理new Date()

    6、不能处理正则

  • lodash.cloneDeep()

  • jQuery.extend()

  • 手写循环递归

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function deepClone(obj, hash = new WeakMap()) {
    if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
    if (obj instanceof Date) return new Date(obj);
    if (obj instanceof RegExp) return new RegExp(obj);
    // 可能是对象或者普通的值 如果是函数的话是不需要深拷贝
    if (typeof obj !== "object") return obj;
    // 是对象的话就要进行深拷贝
    if (hash.get(obj)) return hash.get(obj);
    let cloneObj = new obj.constructor();
    // 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
    hash.set(obj, cloneObj);
    for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
    // 实现一个递归拷贝
    cloneObj[key] = deepClone(obj[key], hash);
    }
    }
    return cloneObj;
    }

总结

前提为拷贝类型为引用类型的情况下:

  • 浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址
  • 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址
  • 本文标题:深浅拷贝
  • 本文作者:灵感胜于汗水
  • 创建时间:2022-11-01 14:09:42
  • 本文链接:https://cjhsyc.github.io/2022/11/01/深浅拷贝/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!