深入理解ES6 007【學習筆記】

Set集合與Map集合

在js中有g一個in運算符,其不需要讀取對象的值就要以判斷屬性在對象中是否存在,如果存在就返回true。但是in運算符也會檢索對象的原型,只有當對象原型為null時使用這個方法才比較穩妥。

Set集合

let set = new Set()
set.add(5)
set.add("5")
console.log(set.size) // 2
const key1={},key2={}
set.add(key1)
set.add(key1)
console.log(set.size) // 4
// 傳入相同值實際上會被忽略
let set1 = new Set(1,2,3,4,5,5,5,5)
console.log(set.size) //5
set1.has(5) //true
set1.has(6) // false
set1.delete(5)
set1.has(5) //false

set1.clear() // 所有元素被清除

set集合中不會對所存值進行強制的類型轉換,數字5和字符串“5”可以作為兩個獨立元素存在(引擎內部使用之前提到過的Object.is()來判斷),如果向Set中添加多個對象則它們之前彼此保持獨立。

Set集合的forEach方法

forEach()方法的回調函數接受以下3個參數

  • Set集合下一次索引位置
  • 與第一個參數一樣的值
  • 被遍歷的Set集合本身

Set集合的forEach()方法與數組中的forEach()方法有一個奇怪的差別:回調函數前兩個參數的值竟然是一樣的。實際上Map集合的forEach()的回調函數都接受3個參數,前兩個分別是值和鍵名。

forEach函數的第二個參數與數組一樣,如果需要回調函數中使用this使用,則可以將它作為第二參數傳入

let set = new Set([1,2])
let processor = {
  output(value){
    console.log(value)
  },
  process(dataSet){
    // 這裡使用箭頭函數,就無須再將this作為第二個參數傳入回調函數了
    dataSet.forEach(function(value){
      this.output(value)
    },this)
  }
}
processor.process(set)

儘管Set集合更適合用來跟蹤多個值,而且又可以通過forEach()方法操作集合中的每一個元素,但是你不能像訪問數組元素那樣直接通過索引訪問集合中的元素。如有需要,最好先將Set集合轉換成一個數組

let set = new Set([1,2,3,3,3,4,5])
arrray = [...set]
console.log(array) // [1,2,3,4,5] 去重

function eliminateDuplicates(items){
  return [...new Set(items)]
}
let numbers = [1,2,3,3,3,4,5],
noDuplicates = eliminateDuplicates(numbers);
console.log(noDuplicates); // [1,2,3,4,5]

Weak Seb集合

將對象存儲在Set的實例中與存儲在變量中一樣,只要Set實例中的引用存在,垃圾回收機制就不能釋放該對象的內存空間,於是之前提到的Set類型可以被看作一個強引用的Set集合。如下

let set = new Set(),
key = {};
set.add(key);
console.log(set.size) // 1
// 移除原始引用
key = null;
console.log(set.size) // 1
// 重新取回原始引用
key = [...set][0]

比如我們使用這個set存儲一個dom對象,當有腳本把這個dom元素刪除掉,那麼set中還保留著這份引用(引起內存洩露),所以ES6引入了一個WeakSet集合。WeakSet只能存儲對象的弱引用,並且不可以存儲原始值;集合中的弱引用如果是對象唯一引用,則會被回收並釋放相應內存。

// 集合支持add()/has()/delete()
let set = new WeakSet(),key = {};
// 向集合添加對象
set.add(key);
console.log(set.has(key)); // true
set.delete(key);
console.log(set.has(key)); // false
let key1 = {}, key2 = {};
set = new WeakSet([key1,key2]) // 如果數組中包含其非對象值,程序會拋出錯誤
console.log(set.has(key1)) // true
console.log(set.has(key2)) // true

// #################
// 移除對象key的最後一個強引用(Weak Set中的引用也自動移除)
let set = new Set(),
key = {};
set.add(key);
console.log(set.has(key)) // true
// 移除對象key的最後個強引用(Weak Set中的引用也自動移除)
key = null;
// 這段代碼執行過後,就無法訪問WeakSet中的key的引用了,由於我們需要向has方法傳遞一個強引用才能驗證這個弱引用是否已被移除了。
  • WeakSet
  • 如果向add/has/delete 3個方法傳入非對象參數會導致程序報錯
  • 不可迭代 不能使用for-of循環
  • 不暴露任何迭代器keysvalues所以無法通過程序本身來檢測其中的內容
  • 不支持forEach
  • 不支持size

Map

  • set
  • get
  • has
  • delete
  • clear
  • size屬性

初始化方法

let map = new Map([["name","Nicholas"],["age",23]])

forEach((value,key,ownerMap)=>{},綁定上下文)

let map = new Map([["name","Nicholas"],["age",23]])
map.forEach(function(value,key,ownerMap){
   console.log(key+" "+value);
   console.log(ownerMap === map)
})

WeakMap

原理跟WeakSet一致的,鍵是對對象的弱引用,而且key只能是存對象

let map = new WeakMap(),
element = document.querySelector('.element');
map.set(element,"Original")
let value = map.get(element)
console.log(value) // Original
// 移除element元素
element.parentNode.removeChild(element);
element = null;
// 此時Weak Map集合為空

私有對象數據

function Person(name){
  this._name = name;
}
Person.prototype.getName = function(){
  return this._name;
}
// 約定前綴為下划線的屬性為私有屬性,不允許在對象實例外改變這個屬性。例如,只能通過getName()方法讀取this._name,所以它也有可能在無意間被覆寫

ES5可以通過以下這種模式創建一個對象接近真正的私有數據

var Person = (function(){
  var privateData = {},
  privateId = 0;
  function Person(name){
    Object.defineProperty(this,"_id",{value:privateId++})
    privateData[this._id] = {
      name:name
    }
  }
  Person.prototype.getName = function(){
    return privateData[this._id].name
  }
  return Person
}())

調用Person構造函數時,屬性_id的值被加1,這個屬性不可枚舉,不可配置且不可寫,上面的代碼最大的問題不能主動管理,由於無法獲取對象實例何時被銷毀,因此privateData中的數據就永遠不會消失。而且使用WeakMap集合可以解決這個問題

let Person = (function(){
  let privateData = new WeakMap();
  function Person(name){
    privateData.set(this,{name:name})
  }
  Person.prototype.getName = function(){
    return privateData.get(this).name
  }
  return Person
}())
// 只要對象實例被銷毀,相關信息也會被銷毀,從而保證了信息的私有性

主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/4333

(0)
Walker的頭像Walker
上一篇 2025年11月25日 14:00
下一篇 2025年11月25日 12:00

相關推薦

  • 深入理解ES6 004【學習筆記】

    擴展對象的功能 普通對象 具有js對象所有默認內部行為的 特異對象 具有某些與默認行為不符的內部行為 標準對象 es6規範中定義的對象,Array/Date等 內建對象 腳本開始執行時存在於javascript執行環境的對象,所有標準對象都是內建對象 對象字面量語法擴展 屬性初始值的簡寫,當一個對象的屬性與本地變量同名時,不必再寫冒號和值 對象方法的簡寫語法…

    個人 2025年3月8日
    1.4K00
  • Go工程師體系課 017【學習筆記】

    限流、熔斷與降級入門(含 Sentinel 實戰) 結合課件第 3 章(3-1 ~ 3-9)的視頻要點,整理一套面向初學者的服務保護指南,幫助理解“為甚麼需要限流、熔斷和降級”,以及如何用 Sentinel 快速上手。 學習路線速覽 3-1 理解服務雪崩與限流、熔斷、降級的背景 3-2 Sentinel 與 Hystrix 對比,明確技術選型 3-3 Sen…

    個人 2025年11月25日
    27900
  • Go工程師體系課 009【學習筆記】

    其它一些功能 個人中心 收藏 管理收貨地址(增刪改查) 留言 拷貝inventory_srv--> userop_srv 查詢替換所有的inventory Elasticsearch 深度解析文檔 1. 甚麼是Elasticsearch Elasticsearch是一個基於Apache Lucene構建的分布式、RESTful搜索和分析引擎,能夠快速地…

    個人 2025年11月25日
    36600
  • 深入理解ES6 008【學習筆記】

    迭代器(Iterator)和生成器(Generator) 這個新特性對於高效的數據處理而言是不可或缺的,你也會發現在語言的其他特性中也都有迭代器的身影:新的for-of循環、展開運算符(...)、甚至連異步編程都可以使用迭代器。 迭代器是一種特殊的對象,它具有一些專門為迭代過程設計的專有接口,所有的迭代器對象都有一個next()方法,每次調用都返回一個結果對…

    個人 2025年3月8日
    1.2K00
  • Go工程師體系課 003【學習筆記】

    grpc grpc grpc-go grpc 無縫集成了 protobuf protobuf 習慣用 Json、XML 數據存儲格式的你們,相信大多都沒聽過 Protocol Buffer。 Protocol Buffer 其實是 Google 出品的一種輕量 & 高效的結構化數據存儲格式,性能比 Json、XML 真的強!太!多! protobuf…

    個人 2025年11月25日
    29700
簡體中文 繁體中文 English