动态

详情 返回 返回

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中堆內存和棧內存簡易示意圖例

image

下面對於對象的操作,都可以參照上圖進行思考

淺拷貝-深拷貝

淺拷貝

只是拷貝了某一層的屬性,或者某一層,沒有全部拷貝到另外的對象上

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中深拷貝和淺拷貝梳理

歡迎關注公眾號:程序員布歐,不定期更新一些技術文章

創作不易,轉載請註明出處和作者。

user avatar cyzf 头像 alijishu 头像 razyliang 头像 leexiaohui1997 头像 anchen_5c17815319fb5 头像 Z-HarOld 头像 munergs 头像 DingyLand 头像 romanticcrystal 头像 it1042290135 头像 huangmingji 头像 abc-x 头像
点赞 85 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.