【JS学习】--深拷贝与浅拷贝

00⭐⭐(!!)深拷贝与浅拷贝

(只谈论了 基本数据类型 和 ES5 的引用数据类型)

(关于 ES6 及之后 新增的Symbol,Map 等数据类型还有待谈论)

(以下仅为 原生JS 的方法,未涉及第三方库使用,第三方库lodash也有函数可实现)

注意:

  • ⭐浅拷贝 与 深拷贝 都是需要开辟新内存地址,产生新对象
  • 但是
  • 浅拷贝 只拷贝 原始对象中的 最外部一层
  • 深拷贝 则会拷贝 原始对象中 所有的层级

Eg:

对于下面这个 对象

const hotGirl = {
    name: 'Maji',
    age: 28,
    info: {
        desc: 'superHot',
    },
};
  • 浅拷贝:
    • 只能拷贝属性nameage拥有新地址,但是 拷贝到 info时 则会引用原始对象 中的地址
    • (!!!即改变原始对象中的info.desc的值时,浅拷贝出来的新对象的info.desc的值同样会改变),
    • 属于不彻底拷贝,所以 只有一层属性的对象 适合浅拷贝。
  • 深拷贝
    • 则可以 完全 拷贝所有层级,变成一个拥有 新地址 的 新对象。属于彻底的拷贝

浅拷贝:只拷贝最外面一层的数据-(不彻底的拷贝)

一 使用Object.assign(target,source01,source02,...)

  • 语法:(将source对象中的值 拷贝到 target目标对象中)

  • target 可以写成空对象

  • **注意:**若target非空 ,且source 和 target中有重复属性 ,则target中的属性会被覆写;target的值会被改变, 但是source的值不会

  • // obj2 拿到的就是 target 
    let obj2 = Object.assign(target,source)
    
Eg: (得到新的对象)
const hotGirl = {
    name: 'Maji',
    age: 28,
};
// target `可以写成空对象`
let newHotGirl = Object.assign({},hotGirl)
console.log(newHotGirl)
// {name: 'Maji', age: 28}

Eg (重新赋值给目标对象)
const hotGirl = {
    name: 'Maji',
    age: 28,
};
const pureGirl = {
    name: 'Olla',
    age: 26,
	tall:"180cm"
};

// 让Olla 从 pureGirl 成为 hotGirl 
// 注意这里 hotGirl 的属性被改变了,pureGirl没有
Object.assign(hotGirl,pureGirl)

// target `可以写成空对象`
console.log(hotGirl)
// {name: 'Olla', age: 26, tall: '180cm'}

二 使用扩展语法 (...)

  • 使用简单,不必多说
const hotGirl = {
    name: 'Maji',
    age: 28,
};
let newHotGirl = { ...hotGirl }
console.log(newHotGirl)
//{name: 'Maji', age: 28}

三 for…in 循环拷贝

const hotGirl = {
    name: 'Maji',
    age: 28,
};

const newHotGirl = {};
//  用 for in 将 obj1 的值拷贝给 obj2
for (let key in hotGirl) {
    //字符串 赋值 就是开辟 新的内存地址,成为完全的新值
    newHotGirl[key] = hotGirl[key];
}
console.log(newHotGirl)
//{name: 'Maji', age: 28}

深拷贝: 每一层数据都会拷贝-(最彻底的拷贝)

一 JSON方法

  • 语法:let newObj = JSON.parse(JSON.stringify(obj))

缺陷(暂不谈论,死记)
  • 会忽略 undefined
  • 会忽略 symbol
  • 会忽略函数:JSON.stringify() 会默认移除函数。
  • JSON.stringify() 无法拷贝 Map、Set、RegExp 这些特殊数据类型。
  • 不能序列化函数 ???
  • 不能解决循环引用的对象 见[前端进阶之道-深浅拷贝](JS | 前端进阶之道 (yuchengkai.cn))

二 ⭐⭐ JS 有原生的深拷贝 API structuredClone

[MDN—structuredClone()](structuredClone() - Web 开发技术 | MDN (mozilla.org))

  • 结构化拷贝算法的实现,能够实现几乎对所有数据类型的深拷贝

  • 该API 较新,兼容要考虑(目前主流都支持) ,虽然有些缺点,但是不影响,放心用,以后应该会加大支持力度

  • 相比 JSON.parse()structuredClone API 的性能更好

  • 语法:

  • let hotGirl = {
        age: 1,
        info: {
            cup: 'E'
        }
    }
    let newHotGirl = structuredClone(hotGirl);
    console.log(newHotGirl)
    
缺点:(死记,放心用,以后会加大支持力度)
  • 原型:无法拷贝对象的原型链。

  • 函数:无法拷贝函数。(普通函数、箭头函数、类、方法)

    • let hotGirl = {
                  age: 1,
                  info: {
                      cup: 'E'
                  },
                  f:function(){
                      console.log('hot')
                  }
              }
              let newHotGirl = structuredClone(hotGirl);
              console.log(newHotGirl)
      
  • DOM节点

  • 不可克隆:并没有支持所有类型的拷贝,比如 Error

三 for … in 手写

完整源码

// 手写深拷贝
export function deepClone(obj) {
  //判断 传入对象 为 数组 或者 对象
  var result = Array.isArray(obj) ? [] : {};
  // for in 遍历
  for (var key in obj) {
    // 判断 是否 为自身 的属性值(排除原型链干扰)
    if (obj.hasOwnProperty(key)) {
      // 判断 对象的属性值 中 存储的 数据类型 是否为对象
      if (typeof obj[key] === 'object') {
        // 有可能等于 null
        if (obj[key] === null ) {
          result[key] = null
          continue  
        }
        // 递归调用
        result[key] = deepClone(obj[key]);   //递归复制
      } 
      // 不是的话 直接 赋值 copy
      else {
        result[key] = obj[key];
      }
    }
  }
  // 返回 新的对象
  return result;
}

补充说明

  • 2022 09 14 在if (typeof obj[key] === 'object')' 之内增加判断null 操作;修复之前(将null 拷贝成 {}的问题)
if (typeof obj[key] === 'object') {
  // 有可能等于 null
  if (obj[key] === null ) {
    result[key] = null
    continue  
  }
  // 递归调用
  result[key] = deepClone(obj[key]);   //递归复制
} 

参考文章

30-浅拷贝和深拷贝 | 千古前端图文教程 (qianguyihao.com)

JS | 前端进阶之道 (yuchengkai.cn)

JS中对象深拷贝:structuredClone()_俊刚的博客-CSDN博客

JS 深拷贝的原生终结者 structuredClone API - 掘金 (juejin.cn)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值