js学习浅拷贝、深拷贝

目录

概念和区别

实现方法

使用场景

实践演练


概念和区别

  1. 深拷贝:深拷贝是指完全复制一个对象,新对象和原对象互不影响,即使原对象发生改变,新对象也不会发生变化。它是将数据从内存中完全拷贝一份创建新的内存区域存储,所以深拷贝后的数据修改不会对原数据有影响。
  2. 浅拷贝:浅拷贝是指只复制一个对象的引用,新旧对象共享一块内存区域。如果原对象中有引用类型的数据,浅拷贝后,新旧对象中的引用类型属性还会共用一块内存区域。因此,如果原对象中的引用类型属性发生改变,新对象中该属性也会跟着改变。

实现方法

  1. 浅拷贝:浅拷贝只需要复制对象的第一层属性,可以使用如下方法
  • Object.assign():使用对象.assign()方法将所有可枚举的属性值从一个或多个源对象复制到目标对象,并返回目标对象。该方法仅复制源对象的第一层属性。
  • 扩展运算符(…):使用三个点(…)展开操作符可以将一个对象复制到新的对象中,也只会复制第一层属性值。
  • 数组的slice()、concat()方法:如果对象是一个数组,可以使用数组的slice()或concat()方法进行浅拷贝。这些方法都只复制目标数组的第一层元素。
  1. 深拷贝:深拷贝需要复制对象的所有属性以及它们的所有嵌套属性,可以使用如下方法
  • 手写递归实现:可以使用递归来遍历对象和它的所有子属性,并复制它们。需要注意的是,在遍历时需要先判断当前属性是否是对象或数组,如果是,则递归进行操作。
  • lodash库的_.cloneDeep()方法:lodash是一个功能强大的JavaScript工具库,它提供了许多有用的方法,其中就包括深拷贝的方法,名为_.cloneDeep()。
  • JSON.parse()和JSON.stringify()方法:可以使用JSON对象提供的parse()和stringify()方法进行深拷贝。该方法的实现原理是将对象序列化为字符串,再将该字符串反序列化成一个新对象,实现了“复制一份新的内存空间”这一目的。但这个方法无法处理对象中的特殊属性,如函数、正则表达式等。

使用场景

浅拷贝

  • 更新数据时需要避免对原数据的修改,同时改变拷贝数据的效率又不能太低,就可以使用浅拷贝。
  • 传递引用类型数据时的特殊使用场景,例如多个组件共用一个数据源的情况下。

深拷贝

  • 处理复杂数据结构时的特殊使用场景,例如多层嵌套的对象、JSON数据、递归处理等。
  • 对象属性值的结构比较复杂,当需要拷贝的对象中包含函数、日期等JS对象就需要使用深拷贝。
  • 在一些需要对原数据做出修改并保存又保证原数据不受更改的情况下,可以使用深拷贝。

实践演练

首先我们先定义一个需要被拷贝的对象:

const obj = {
  name: 'Alice',
  age: 20,
  education: {
    school: 'AAA University',
    major: 'Computer Science'
  },
  skills: ['JavaScript', 'React', 'Node.js']
};
  1. 浅拷贝(使用扩展运算符或Object.assign()方法进行浅拷贝):
// 扩展运算符方式
const objShallow1 = { ...obj };

// Object.assign()方式
const objShallow2 = Object.assign({}, obj);

console.log('浅拷贝结果:');
console.log(objShallow1);
console.log(objShallow2);

//浅拷贝结果:
{
  name: 'Alice',
  age: 20,
  education: {
    school: 'AAA University',
    major: 'Computer Science'
  },
  skills: ['JavaScript', 'React', 'Node.js']
}
{
  name: 'Alice',
  age: 20,
  education: {
    school: 'AAA University',
    major: 'Computer Science'
  },
  skills: ['JavaScript', 'React', 'Node.js']
}

可以看到,两种浅拷贝方式都成功地对原对象进行了拷贝,新对象和原对象的第一层属性值相同,但嵌套在第一层属性中的引用类型的值(如education和skills)是浅拷贝得到的新对象和原对象中共享的,修改一个对象的这些属性值会影响另一个对象。 

  1. 深拷贝(使用手动递归的方式,或使用第三方库如lodash库的_.cloneDeep()方法进行深拷贝):
// 手动递归实现深拷贝
function deepClone(obj) {
  let newObj = Array.isArray(obj) ? [] : {};
  if (obj && typeof obj === 'object') {
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        newObj[key] = deepClone(obj[key]);
      }
    }
  } else {
    newObj = obj;
  }
  return newObj;
}

// lodash的深拷贝方法
const _ = require('lodash');

const objDeep1 = deepClone(obj);
const objDeep2 = _.cloneDeep(obj);

console.log('深拷贝结果:');
console.log(objDeep1);
console.log(objDeep2);


//深拷贝结果:
{
  name: 'Alice',
  age: 20,
  education: {
    school: 'AAA University',
    major: 'Computer Science'
  },
  skills: ['JavaScript', 'React', 'Node.js']
}
{
  name: 'Alice',
  age: 20,
  education: {
    school: 'AAA University',
    major: 'Computer Science'
  },
  skills: ['JavaScript', 'React', 'Node.js']
}

可以看到,两种深拷贝方式都成功地对原对象进行了全量拷贝,新对象和原对象互不干扰,修改一个对象的属性值不会影响另一个对象。

在实际开发中,我们需要根据实际情况决定采用深拷贝还是浅拷贝。当我们要对数据进行修改但是不能修改源数据时,需要使用深拷贝。而在需要复制引用类型数据但无需修改原始数据的情况下,可以使用浅拷贝。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值