乐趣区

关于javascript:javaScript深拷贝和浅拷贝简单梳理

在理解深拷贝和浅拷贝之前,咱们先梳理一下:

JavaScript 中,分为根本数据类型(原始值)和简单类型(对象),同时它们各自的数据类型细分下又有好几种数据类型

根本数据类型

数字 Number 字符串 String 布尔 Boolean Null Undefined Symbols BigInt

根本数据类型在内存当中,是存储在栈 Stack

在数据结构当中

  • 栈在内存上的调配的空间生命周期很短,当变量应用结束,办法执行实现就被开释掉,因而在 js 当中,变量应用结束之后,根本就被回收了,
  • 有一个场景比拟例外,闭包的状况下,变量是始终存在内存当中不被开释.
  • 栈存储具备先进后出,后进先出的特点: 1,2,3,4,5,6 => 6,5,4,3,2,1

援用数据类型

日期 Dete,对象 Object,数组 Array, 办法 Function, 正则 regex, 带键的汇合:Maps, Sets, WeakMaps, WeakSets

援用数据类型与堆内存 heap 的一些关系
  • 在 JavaScript 中,不容许间接拜访堆内存中的地位,不能间接操作对象的堆内存空间。
  • 对象的援用地址是存在栈内存中,在咱们的日常编码过程中,操作对象的时候,读取对象的存在栈内存的援用地址而不是在堆中的对象,援用类型的值都是通过援用拜访。

JavaScript 中堆内存和栈内存繁难示意图例

上面对于对象的操作,都能够参照上图进行思考

浅拷贝 - 深拷贝

浅拷贝

只是拷贝了某一层的属性,或者某一层,没有全副拷贝到另外的对象上

let userInfo = {
  name: "zhangsan",
  age: "29",
  say: function () {console.log("hello");
  },
  child: [
    {name: "zhangsan01",},
  ],
};
  1. 对象解构, 只能拷贝第一层对象

    // 对象解构...
    let info = {...userInfo};
    info.name = "lisi";
    info.child.name = "lisi001";
    info.say();
    
    console.log("userInfo", userInfo);
    console.log("info", info);
    
    userInfo 和 info 中的 child.name 都改成了 ---->"lisi001"
    
  2. Object.assign() 第一层是深拷贝,二级属性后就是浅拷贝
let info = {};
Object.assign(info, userInfo);
info.name = "lisi";
info.child.name = "lisi001";
console.log("userInfo", userInfo);
console.log("info", info);
  1. JSON.parse(JSON.stringify());
    对象能够复制,然而当属性是 function 时,没有复制到新的对象上,因而在日常的开发过程中,波及到数组对象,应用 JSON.parse(JSON.stringify()); 还是没问题的

    let info = JSON.parse(JSON.stringify(userInfo));
    info.name = "lisi";
    info.child.name = "lisi001";
    console.log("userInfo", userInfo);
    console.log("info", info);
    
  2. for in,第一层能够拷贝,第二层在批改的时候,还是应用的援用地址,前后的对象都产生了更改

    let info = {};
    for (let key in userInfo) {info[key] = userInfo[key];
    }
    info.name = "lisi";
    info.child.name = "lisi001";
    console.log("userInfo", userInfo);
    console.log("info", info);

浅拷贝小结

以上浅拷贝办法,有些拷贝只能拷贝第一层,有些能够拷贝多层,
然而当属性类型是办法时,还是浅拷贝,
因而咱们在开发中,应用浅拷贝,须要留神,同时,出了拷贝 function,相似正则,date 等数据类型没有一一列举,感兴趣的同学能够本人写一些 demo,去校验更为简单和数据类型更丰盛的数据。

深拷贝

所有的属性都拷贝到新的对象上

  1. 应用递归遍历每一个属性,在递归遍历的时候,针对每一种数据类型解决和拷贝
  2. lodash 深拷贝办法,感兴趣的同学,能够去浏览 lodash 深拷贝的实现源码

文档地址:深拷贝 cloneDeep https://www.lodashjs.com/docs/lodash.cloneDeep

  1. 更多办法,有待补充

结尾

  • 当咱们操作简单数据类型的时候,都是在操作栈内存 Stack 的内存地址,指针指向对象在堆内存 heap 的数据。
  • 传入的对象是应用对象字面量 {} 创立的对象还是由构造函数生成的对象
  • 如果对象是由构造函数创立进去的,那么是否要拷贝原型链上的属性
  • 如果要拷贝原型链上的属性,那么如果原型链上存在多个同名的属性,保留哪个
  • 针对的数据类型,属性的数据类型,各自的缺点,实用的业务场景,本人造轮子 or 应用原生办法,工具类

源码地址

  • 码云 https://gitee.com/lewyon/vue-note
  • githup https://github.com/akari16/vue-note

文章集体博客地址:javaScript 中深拷贝和浅拷贝梳理

欢送关注公众号:程序猿布欧,不定期更新一些前端入门文章

创作不易,转载请注明出处和作者。

退出移动版