彻底理解js中的深浅拷贝

数据类型

说到深浅拷贝就不得不说到 js 的数据类型,在 js 中有两大数据类型基本数据类型,引用数据类型。 基本数据类型是存储在内存中,引用数据类型存储在内存中,引用数据类型的变量是一个指向堆内存的的引用,是一个地址值,存在栈中。

浅拷贝

浅拷贝是指创建一份跟原始数据值相同的复制品;规则额是这样的,如果是基本数据类型就拷贝基本类型的值,如果是引用数据类型就拷贝内存地址。也可以这么说浅拷贝就是拷贝一层,深层次的引用类型数据就共享内存地址。 用原生 js 实现一个浅拷贝如下:

js 复制代码
function shallowClone(obj) {
  const shallowObj = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      shallowObj[key] = obj[key];
    }
  }
  return shallowObj;
}

在 js 中原生提供了一些方法供我们实现浅拷贝

  1. Object.assign()
  2. Array.prototype.slice()
  3. Array.prototype.concat()
  4. es6 提供的拓展运算符

看一些例子

Object.assign()

js 复制代码
const obj = {
  name: "zhangsan",
  age: 18,
  hobby: ["apple", "banana"],
  address: {
    province: "省",
    city: "市",
    area: "区",
  },
  say: function () {
    console.log("hello");
  },
};

const newObj = Object.assign({}, obj);

Array.prototype.slice()

js 复制代码
const arr = [1,2,3],
const newArr = arr.slice(0)
newArr[0] = 2
// arr [1,2,3]
// newArr [2,2,3]

Array.prototype.concat()

js 复制代码
const arr = [1, 2, 3];
const newArr = arr.concat();
newArr[0] = 2;
// arr [1,2,3]
// newArr [2,2,3]

ES6 扩展运算符

js 复制代码
const arr = [1, 2, 3];
const newArr = [...arr];
newArr[0] = 2;
// arr [1,2,3]
// newArr [2,2,3]
// 对象同理
const obj = { a: 1, b: 2 };
const newObj = { ...obj };
newObj[a] = 2;
// obj { a: 1, b: 2 }
// newObj { a: 2, b: 2 }

深拷贝

对于基本数据类型来说深拷贝浅拷贝都是一样的,对于引用数据类型来说,深拷贝就是新开一块内存空间,存放的是一份和原始值一样的数据但是内存地址是不同的,所以修改新对象的属性并不会改变原始对象的属性。

常用的深拷贝方法

  1. lodash 中的 cloneDeep
  2. JSON.stringify() 该方式有很大弊端,当遇到函数、undefined、symbol 时会无法复制,且无法解决循环引用
  3. js 原生手写递归深拷贝函数

原生实现一个深拷贝函数

js 复制代码
function cloneDeep(obj, hash = new WeakMap()) {
  // 如果是null直接return
  if (obj === null) return obj;
  // Date
  if (obj instanceof Date) return new Date(obj);
  // Reg
  if (obj instanceof RegExp) return new RegExp(obj);
  // 如果是基本属性类型或者函数直接return
  if (typeof obj !== "object") return obj;
  // 如果是对象且缓存中有值,直接从缓存中取值
  if (hash.get(obj)) return hash.get(obj);
  // 以obj原型的constructor创建一个新对象,因为它指向当前类本身
  const cloneObj = new obj.constructor();
  hash.set(obj, cloneObj);
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 递归
      cloneObj[key] = cloneDeep(obj[key], hash);
    }
  }
  return cloneObj;
}
相关推荐
程序员黑豆3 分钟前
鸿蒙开发:RelativeContainer相对布局组件实战——实现5个文本组件对齐
前端·华为·harmonyos
环境栈笔记10 分钟前
高性价比指纹浏览器推荐与选型:如何对照价格和实际可用功能筛选候选
前端·人工智能·后端·自动化
hyf32663324 分钟前
泛程序哪有想象中难!小白跟着走一遍就全懂
前端·爬虫·搜索引擎·seo·蜘蛛池
码农学院36 分钟前
React公众号开发:母婴用品会员积分体系技术方案
前端·react.js·前端框架
路光.1 小时前
Vue2升级Vue3处理原 UMD/CommonJS 打包文件,不是标准 ESM
前端·javascript·vue.js·vue3
黄华SJ520it1 小时前
门店预约系统开发:提升服务行业数字化转型
前端·数据库·系统开发
一只月月鸟呀2 小时前
移动端tap与click的区别 && 点透事件
开发语言·前端·javascript
雪隐2 小时前
AI股票小助手10-我用代码管住自己的手:一个普通人的市场观察笔记
前端·人工智能·后端
KaMeidebaby3 小时前
卡梅德生物技术快报|抗体筛选:抗体筛选中的噬菌体展示四参数调优——从流程设计到数据验证
开发语言·前端·javascript
甲维斯3 小时前
Opus5.0首测,瘫坐沙发!效果,时间,token皆无敌!
前端·人工智能