深拷贝、浅拷贝、区别?如何实现?

前言

  • 基本数据存储在中(先进后出)
  • 引用数据指针存储在中,数据存储在
  • 深拷贝和浅拷贝是针引用(复杂)数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝

浅拷贝

  • 浅拷贝 基本类型的数据 - 拷贝的就是基本类型的
  • 浅拷贝 引用类型的数据 - 共享内存地址

javaScript中存在浅拷贝的现象有:

  • 使用扩展运算符实现的数组和对象的复制
  • Object.assign(obj1, obj2)
  • Array.prototype.slice() 语法: arr.slice(start, end)
  • Array.prototype.concat() 语法:arr= arr1.concat(arr2, arr3, arr4)
  • lodash 里面的 _.clone

浅拷贝代码实现:

scss 复制代码
function shallowClone(obj) {
    const newObj = {};
    for(let prop in obj) {
        if(obj.hasOwnProperty(prop)){
            // 未判断obj[prop]的数据类型 仅仅拷贝了一层
            newObj[prop] = obj[prop];
        }
    }
    return newObj;
}

深拷贝

深拷贝就是把一个对象,从内存中完整的拷贝出来,从堆内存中开辟了新区域,用来存新对象,并且修改新对象不会影响原对象

常见的深拷贝:

  • _.cloneDeep() 语法: obj2=_.cloneDeep(bj1)
  • jQuery.extend() 语法:obj2 = $.extend(true, {}, obj1)
  • JSON.parse(JSON.stringify())语法:obj2=JSON.parse(JSON.stringify(obj1))
  • 手写递归

1、_.cloneDeep()

ini 复制代码
const _ = require('lodash');
const obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
const obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false

2、jQuery.extend()

ini 复制代码
const $ = require('jquery');
const obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
const obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false

3、JSON.parse(JSON.stringify())

javascript 复制代码
const obj2=JSON.parse(JSON.stringify(obj1))

但是这种方式存在弊端,会忽略 undefined symbol 函数

javascript 复制代码
const obj = {
    name: 'A',
    name1: undefined,
    name3: function() {},
    name4: Symbol('A')
}

const obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); // {name: "A"}

4、循环递归

javascript 复制代码
// WeakMap是JavaScript中的一种内置数据结构,它是一种特殊的映射(Map),用于存储键值对
// 与普通的Map不同,WeakMap的键必须是对象
function deepClone(obj, hash = new WeakMap()) {
    // 如果是null 或者 undeind 不进行拷贝操作
    if (obj === null) return obj; 
    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;
}

总结

浅拷贝和深拷贝都创建出一个新的对象,但在复制对象属性的时候,行为就不一样。浅拷贝只复制属性指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,修改对象属性会影响原对象。

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

  • 浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址
  • 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址
相关推荐
IT_陈寒21 分钟前
Python 3.12 新特性实战:5个让你的代码效率提升50%的技巧!🔥
前端·人工智能·后端
Apifox23 分钟前
Apifox 8 月更新|新增测试用例、支持自定义请求示例代码、提升导入/导出 OpenAPI/Swagger 数据的兼容性
前端·后端·测试
weixin_5412999425 分钟前
VSCode: 从插件安装到配置,如何实现 Ctrl+S 保存时,完全按照 .eslintrc.js 中的 ESLint 规则自动格式化代码
javascript·ide·vscode
yw00yw25 分钟前
常见的设计模式
开发语言·javascript·设计模式
coding随想30 分钟前
最后的挽留:深入浅出HTML5 beforeunload事件
前端
叶浩成52034 分钟前
WebSocket实时通信系统——js技能提升
javascript·websocket·网络协议
亚里士多德芙43 分钟前
记录:离线包实现桥接
前端
去伪存真1 小时前
用的好好的vue.config.js代理,突然报308, 怎么回事?🤔
前端
搞个锤子哟1 小时前
el-select使用filter-method实现自定义过滤
前端
flyliu1 小时前
什么是单点登录,如何实现
前端