“睡服”面试官系列第六篇之set数据结构(建议收藏学习)
目錄
set
1基本用法
2Set 實例的屬性和方法
3遍歷操作
3.1?keys() , values() , entries()
3.2 forEach()
3.3遍歷的應用
weakset
含義
語法
總結
set
1基本用法
ES6 提供了新的數據結構 Set。它類似于數組,但是成員的值都是唯一的,沒有重復的值。
Set 本身是一個構造函數,用來生成 Set 數據結構。
上面代碼通過 add 方法向 Set 結構加入成員,結果表明 Set 結構不會添加重復的值。
Set 函數可以接受一個數組(或者具有 iterable 接口的其他數據結構)作為參數,用來初始化。
上面代碼中,例一和例二都是 Set 函數接受數組作為參數,例三是接受類似數組的對象作為參數。
上面代碼中,也展示了一種去除數組重復成員的方法。
向 Set 加入值的時候,不會發生類型轉換,所以 5 和 "5" 是兩個不同的值。Set 內部判斷兩個值是否不同,使用的算法叫做“Same-value equality”,它
類似于精確相等運算符( === ),主要的區別是 NaN 等于自身,而精確相等運算符認為 NaN 不等于自身。
上面代碼向 Set 實例添加了兩個 NaN ,但是只能加入一個。這表明,在 Set 內部,兩個 NaN 是相等。
另外,兩個對象總是不相等的
上面代碼表示,由于兩個空對象不相等,所以它們被視為兩個值
2Set 實例的屬性和方法
Set 結構的實例有以下屬性。
Set.prototype.constructor :構造函數,默認就是 Set 函數。
Set.prototype.size :返回 Set 實例的成員總數。
Set 實例的方法分為兩大類:操作方法(用于操作數據)和遍歷方法(用于遍歷成員)。下面先介紹四個操作方法。
add(value) :添加某個值,返回 Set 結構本身。
delete(value) :刪除某個值,返回一個布爾值,表示刪除是否成功。
has(value) :返回一個布爾值,表示該值是否為 Set 的成員。
clear() :清除所有成員,沒有返回值。
上面這些屬性和方法的實例如下。
下面是一個對比,看看在判斷是否包括一個鍵上面, Object 結構和 Set 結構的寫法不同
// 對象的寫法 const properties = { 'width': 1, 'height': 1 }; if (properties[someName]) { // do something } // Set的寫法 const properties = new Set(); properties.add('width'); properties.add('height'); if (properties.has(someName)) { // do something }Array.from 方法可以將 Set 結構轉為數組。
const items = new Set([1, 2, 3, 4, 5]); const array = Array.from(items);這就提供了去除數組重復成員的另一種方法。
function dedupe(array) { return Array.from(new Set(array)); } dedupe([1, 1, 2, 3]) // [1, 2, 3]3遍歷操作
Set 結構的實例有四個遍歷方法,可以用于遍歷成員。
keys() :返回鍵名的遍歷器
values() :返回鍵值的遍歷器
entries() :返回鍵值對的遍歷器
forEach() :使用回調函數遍歷每個成員
需要特別指出的是, Set 的遍歷順序就是插入順序。這個特性有時非常有用,比如使用 Set 保存一個回調函數列表,調用時就能保證按照添加順序調用。
3.1?keys() , values() , entries()
keys 方法、 values 方法、 entries 方法返回的都是遍歷器對象(詳見《Iterator 對象》一章)。由于 Set 結構沒有鍵名,只有鍵值(或者說鍵名和鍵值
是同一個值),所以 keys 方法和 values 方法的行為完全一致。
上面代碼中, entries 方法返回的遍歷器,同時包括鍵名和鍵值,所以每次輸出一個數組,它的兩個成員完全相等。
Set 結構的實例默認可遍歷,它的默認遍歷器生成函數就是它的 values 方法。
這意味著,可以省略 values 方法,直接用 for...of 循環遍歷 Set。
let set = new Set(['red', 'green', 'blue']); for (let x of set) { console.log(x); } // red // green // blue3.2 forEach()
Set 結構的實例與數組一樣,也擁有 forEach 方法,用于對每個成員執行某種操作,沒有返回值。
上面代碼說明, forEach 方法的參數就是一個處理函數。該函數的參數與數組的 forEach 一致,依次為鍵值、鍵名、集合本身(上例省略了該參數)。這
里需要注意,Set 結構的鍵名就是鍵值(兩者是同一個值),因此第一個參數與第二個參數的值永遠都是一樣的。
另外, forEach 方法還可以有第二個參數,表示綁定處理函數內部的 this 對象。
3.3遍歷的應用
擴展運算符( ... )內部使用 for...of 循環,所以也可以用于 Set 結構。
擴展運算符和 Set 結構相結合,就可以去除數組的重復成員
let arr = [3, 5, 2, 2, 5, 5]; let unique = [...new Set(arr)]; // [3, 5, 2]而且,數組的 map 和 filter 方法也可以用于 Set 了。
let set = new Set([1, 2, 3]); set = new Set([...set].map(x => x * 2)); // 返回Set結構:{2, 4, 6} let set = new Set([1, 2, 3, 4, 5]); set = new Set([...set].filter(x => (x % 2) == 0)); // 返回Set結構:{2, 4}因此使用 Set 可以很容易地實現并集(Union)、交集(Intersect)和差集(Difference)。
let a = new Set([1, 2, 3]); let b = new Set([4, 3, 2]); // 并集 let union = new Set([...a, ...b]); // Set {1, 2, 3, 4} // 交集 let intersect = new Set([...a].filter(x => b.has(x))); // set {2, 3} // 差集 let difference = new Set([...a].filter(x => !b.has(x))); // Set {1}如果想在遍歷操作中,同步改變原來的 Set 結構,目前沒有直接的方法,但有兩種變通方法。一種是利用原 Set 結構映射出一個新的結構,然后賦值給原
來的 Set 結構;另一種是利用 Array.from 方法
上面代碼提供了兩種方法,直接在遍歷操作中改變原來的 Set 結構。
weakset
含義
WeakSet 結構與 Set 類似,也是不重復的值的集合。但是,它與 Set 有兩個區別。
首先,WeakSet 的成員只能是對象,而不能是其他類型的值
上面代碼試圖向 WeakSet 添加一個數值和 Symbol 值,結果報錯,因為 WeakSet 只能放置對象。
其次,WeakSet 中的對象都是弱引用,即垃圾回收機制不考慮 WeakSet 對該對象的引用,也就是說,如果其他對象都不再引用該對象,那么垃圾回收機
制會自動回收該對象所占用的內存,不考慮該對象還存在于 WeakSet 之中。
這是因為垃圾回收機制依賴引用計數,如果一個值的引用次數不為 0 ,垃圾回收機制就不會釋放這塊內存。結束使用該值之后,有時會忘記取消引用,導
致內存無法釋放,進而可能會引發內存泄漏。WeakSet 里面的引用,都不計入垃圾回收機制,所以就不存在這個問題。因此,WeakSet 適合臨時存放一
組對象,以及存放跟對象綁定的信息。只要這些對象在外部消失,它在 WeakSet 里面的引用就會自動消失。
由于上面這個特點,WeakSet 的成員是不適合引用的,因為它會隨時消失。另外,由于 WeakSet 內部有多少個成員,取決于垃圾回收機制有沒有運行,
運行前后很可能成員個數是不一樣的,而垃圾回收機制何時運行是不可預測的,因此 ES6 規定 WeakSet 不可遍歷。
這些特點同樣適用于本章后面要介紹的 WeakMap 結構
語法
WeakSet 是一個構造函數,可以使用 new 命令,創建 WeakSet 數據結構
const ws = new WeakSet();作為構造函數,WeakSet 可以接受一個數組或類似數組的對象作為參數。(實際上,任何具有 Iterable 接口的對象,都可以作為 WeakSet 的參數。)
該數組的所有成員,都會自動成為 WeakSet 實例對象的成員。
上面代碼中, a 是一個數組,它有兩個成員,也都是數組。將 a 作為 WeakSet 構造函數的參數, a 的成員會自動成為 WeakSet 的成員。
注意,是 a 數組的成員成為 WeakSet 的成員,而不是 a 數組本身。這意味著,數組的成員只能是對象
上面代碼中,數組 b 的成員不是對象,加入 WeaKSet 就會報錯。
WeakSet 結構有以下三個方法。
WeakSet.prototype.add(value):向 WeakSet 實例添加一個新成員。
WeakSet.prototype.delete(value):清除 WeakSet 實例的指定成員。
WeakSet.prototype.has(value):返回一個布爾值,表示某個值是否在 WeakSet 實例之中。
下面是一個例子。
const ws = new WeakSet(); const obj = {}; const foo = {}; ws.add(window); ws.add(obj); ws.has(window); // true ws.has(foo); // false ws.delete(window); ws.has(window); // falseWeakSet 沒有 size 屬性,沒有辦法遍歷它的成員。
ws.size // undefined ws.forEach // undefined ws.forEach(function(item){ console.log('WeakSet has ' + item)}) // TypeError: undefined is not a function上面代碼試圖獲取 size 和 forEach 屬性,結果都不能成功。
WeakSet 不能遍歷,是因為成員都是弱引用,隨時可能消失,遍歷機制無法保證成員的存在,很可能剛剛遍歷結束,成員就取不到了。WeakSet 的一個
用處,是儲存 DOM 節點,而不用擔心這些節點從文檔移除時,會引發內存泄漏。
下面是 WeakSet 的另一個例子。
上面代碼保證了 Foo 的實例方法,只能在 Foo 的實例上調用。這里使用 WeakSet 的好處是, foos 對實例的引用,不會被計入內存回收機制,所以刪除實
例的時候,不用考慮 foos ,也不會出現內存泄漏。
總結
本博客源于本人閱讀相關書籍和視頻總結,創作不易,謝謝點贊支持。學到就是賺到。我是歌謠,勵志成為一名優秀的技術革新人員。
歡迎私信交流,一起學習,一起成長。
推薦鏈接 其他文件目錄參照
“睡服“面試官系列之各系列目錄匯總(建議學習收藏)
總結
以上是生活随笔為你收集整理的“睡服”面试官系列第六篇之set数据结构(建议收藏学习)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对了,CSDN博客有搬家工具没
- 下一篇: 前端学习(1765):前端调试值之性能分