<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【基礎(chǔ)復(fù)盤】ES6中 的 WeakMap 你會用了嗎?

          共 5163字,需瀏覽 11分鐘

           ·

          2022-09-06 09:01

          大廠技術(shù) ?? 高級前端 ?? Node進(jìn)階

          點擊上方? 程序員成長指北 ,關(guān)注公眾號

          回復(fù) 1 ,加入高級Node交流群

          前言

          我們先從 WeakMap 的特性說起,然后聊聊 WeakMap 的一些應(yīng)用場景。

          特性

          1. WeakMap 只接受對象作為鍵名

              const map = new WeakMap();
          map.set(1, 2);
          // TypeError: Invalid value used as weak map key
          map.set(null, 2);
          // TypeError: Invalid value used as weak map key

          2. WeakMap 的鍵名所引用的對象是弱引用

          我個人覺得這句話真正想表達(dá)的意思應(yīng)該是:

              WeakMaps hold "weak" references to key objects,

          翻譯過來應(yīng)該是 WeakMaps 保持了對鍵名所引用的對象的弱引用。

          我們先聊聊弱引用:

          在計算機(jī)程序設(shè)計中,弱引用與強(qiáng)引用相對,是指不能確保其引用的對象不會被垃圾回收器回收的引用。一個對象若只被弱引用所引用,則被認(rèn)為是不可訪問(或弱可訪問)的,并因此可能在任何時刻被回收。

          在 JavaScript 中,一般我們創(chuàng)建一個對象,都是建立一個強(qiáng)引用:

              var obj = new Object();

          只有當(dāng)我們手動設(shè)置?obj = null?的時候,才有可能回收 obj 所引用的對象。

          而如果我們能創(chuàng)建一個弱引用的對象:

              // 假設(shè)可以這樣創(chuàng)建一個
          var obj = new WeakObject();

          我們什么都不用做,只用靜靜的等待垃圾回收機(jī)制執(zhí)行,obj 所引用的對象就會被回收。

          我們再來看看這句:

          WeakMaps 保持了對鍵名所引用的對象的弱引用

          正常情況下,我們舉個例子:

              const key = new Array(5 * 1024 * 1024);
          const arr = [
          [key, 1]
          ];

          使用這種方式,我們其實建立了 arr 對 key 所引用的對象(我們假設(shè)這個真正的對象叫 Obj)的強(qiáng)引用。

          所以當(dāng)你設(shè)置?key = null?時,只是去掉了 key 對 Obj 的強(qiáng)引用,并沒有去除 arr 對 Obj 的強(qiáng)引用,所以 Obj 還是不會被回收掉。

          Map 類型也是類似:

              let map = new Map();
          let key = new Array(5 * 1024 * 1024);

          // 建立了 map key 所引用對象的強(qiáng)引用
          map.set(key, 1);
          // key = null 不會導(dǎo)致 key 的原引用對象被回收
          key = null;

          我們可以通過 Node 來證明一下這個問題:

              // 允許手動執(zhí)行垃圾回收機(jī)制
          node --expose-gc

          global.gc();
          // 返回 Nodejs 的內(nèi)存占用情況,單位是 bytes
          process.memoryUsage(); // heapUsed: 4640360 4.4M

          let map = new Map();
          let key = new Array(5 * 1024 * 1024);
          map.set(key, 1);
          global.gc();
          process.memoryUsage(); // heapUsed: 46751472 注意這里大約是 44.6M

          key = null;
          global.gc();
          process.memoryUsage(); // heapUsed: 46754648 44.6M

          // 這句話其實是無用的,因為 key 已經(jīng)是 null
          map.delete(key);
          global.gc();
          process.memoryUsage(); // heapUsed: 46755856 44.6M

          如果你想要讓 Obj 被回收掉,你需要先?delete(key)?然后再?key = null:

              let map = new Map();
          let key = new Array(5 * 1024 * 1024);
          map.set(key, 1);
          map.delete(key);
          key = null;

          我們依然通過 Node 證明一下:

              node --expose-gc

          global.gc();
          process.memoryUsage(); // heapUsed: 4638376 4.4M

          let map = new Map();
          let key = new Array(5 * 1024 * 1024);
          map.set(key, 1);
          global.gc();
          process.memoryUsage(); // heapUsed: 46727816 44.6M

          map.delete(key);
          global.gc();
          process.memoryUsage(); // heapUsed: 46748352 44.6M

          key = null;
          global.gc();
          process.memoryUsage(); // heapUsed: 4808064 4.6M

          這個時候就要說到 WeakMap 了:

              const wm = new WeakMap();
          let key = new Array(5 * 1024 * 1024);
          wm.set(key, 1);
          key = null;

          當(dāng)我們設(shè)置?wm.set(key, 1)?時,其實建立了 wm 對 key 所引用的對象的弱引用,但因為?let key = new Array(5 * 1024 * 1024)?建立了 key 對所引用對象的強(qiáng)引用,

          被引用的對象并不會被回收,但是當(dāng)我們設(shè)置?key = null?的時候,就只有 wm 對所引用對象的弱引用,下次垃圾回收機(jī)制執(zhí)行的時候,該引用對象就會被回收掉。

          我們用 Node 證明一下:

              node --expose-gc

          global.gc();
          process.memoryUsage(); // heapUsed: 4638992 4.4M

          const wm = new WeakMap();
          let key = new Array(5 * 1024 * 1024);
          wm.set(key, 1);
          global.gc();
          process.memoryUsage(); // heapUsed: 46776176 44.6M

          key = null;
          global.gc();
          process.memoryUsage(); // heapUsed: 4800792 4.6M

          所以 WeakMap 可以幫你省掉手動刪除對象關(guān)聯(lián)數(shù)據(jù)的步驟,所以當(dāng)你不能或者不想控制關(guān)聯(lián)數(shù)據(jù)的生命周期時就可以考慮使用 WeakMap。

          總結(jié)這個弱引用的特性,就是 WeakMaps 保持了對鍵名所引用的對象的弱引用,即垃圾回收機(jī)制不將該引用考慮在內(nèi)。只要所引用的對象的其他引用都被清除,垃圾回收機(jī)制就會釋放該對象所占用的內(nèi)存。也就是說,一旦不再需要,WeakMap 里面的鍵名對象和所對應(yīng)的鍵值對會自動消失,不用手動刪除引用。

          也正是因為這樣的特性,WeakMap 內(nèi)部有多少個成員,取決于垃圾回收機(jī)制有沒有運行,運行前后很可能成員個數(shù)是不一樣的,而垃圾回收機(jī)制何時運行是不可預(yù)測的,因此 ES6 規(guī)定 WeakMap 不可遍歷。

          所以 WeakMap 不像 Map,一是沒有遍歷操作(即沒有keys()、values()和entries()方法),也沒有 size 屬性,也不支持 clear 方法, 所以 WeakMap只有四個方法可用:get()、set()、has()、delete()。

          應(yīng)用

          1. 在 DOM 對象上保存相關(guān)數(shù)據(jù)

          傳統(tǒng)使用 jQuery 的時候,我們會通過 $.data() 方法在 DOM 對象上儲存相關(guān)信息(就比如在刪除按鈕元素上儲存帖子的 ID 信息),jQuery 內(nèi)部會使用一個對象管理 DOM 和對應(yīng)的數(shù)據(jù), 當(dāng)你將 DOM 元素刪除,DOM 對象置為空的時候,相關(guān)聯(lián)的數(shù)據(jù)并不會被刪除,你必須手動執(zhí)行 $.removeData() 方法才能刪除掉相關(guān)聯(lián)的數(shù)據(jù),WeakMap 就可以簡化這一操作:

              let wm = new WeakMap(), element = document.querySelector(".element");
          wm.set(element, "data");

          let value = wm.get(elemet);
          console.log(value); // data

          element.parentNode.removeChild(element);
          element = null;

          2. 數(shù)據(jù)緩存

          從上一個例子,我們也可以看出,當(dāng)我們需要關(guān)聯(lián)對象和數(shù)據(jù),比如在不修改原有對象的情況下儲存某些屬性或者根據(jù)對象儲存一些計算的值等,而又不想管理這些數(shù)據(jù)的死活時非常適合考慮使用 WeakMap。

          數(shù)據(jù)緩存就是一個非常好的例子:

              const cache = new WeakMap();
          function countOwnKeys(obj) {
          if (cache.has(obj)) {
          console.log('Cached');
          return cache.get(obj);
          } else {
          console.log('Computed');
          const count = Object.keys(obj).length;
          cache.set(obj, count);
          return count;
          }
          }

          3. 私有屬性

          WeakMap 也可以被用于實現(xiàn)私有變量,不過在 ES6 中實現(xiàn)私有變量的方式有很多種,這只是其中一種:

              const privateData = new WeakMap();

          class Person {
          constructor(name, age) {
          privateData.set(this, { name: name, age: age });
          }

          getName() {
          return privateData.get(this).name;
          }

          getAge() {
          return privateData.get(this).age;
          }
          }

          export default Person;
              Node 社群
                      



          我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學(xué)習(xí)感興趣的話(后續(xù)有計劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。



          如果你覺得這篇內(nèi)容對你有幫助,我想請你幫我2個小忙:

          1. 點個 「在看」 ,讓更多人也能看到這篇文章 2. 訂閱官方博客? www.inode.club? 讓我們一起成長

          點贊和在看就是最大的支持 ??

          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  北条麻妃成人视频 | 国产无码激情后入 | 俺来俺去www色官网 | 中文字幕日韩一级 | 黄色欧美精品 |