新的數據結構
目錄:
無序集合 Set
數組與集合的區別
數組 | 集合 | |
---|---|---|
元素序列 | 有序 | 無序 |
元素可重複性 | 元素可重複 | 元素不可重複 |
用法:new Set([iterable]) : Set
const set = new Set();
const set = new Set([1, 2, 3]);
增減元素
通過 add、delete 和 clear 方法來添加、刪除和清空集合內的元素。
const set = new Set();
// 添加元素
set
.add(1)
.add(2)
.add(3)
.add(3); // 這一句並不會起到任何作用,因爲元素3已存在
console.log(set); // Set(3) {1, 2, 3}
// 刪除元素
set.delete(2);
console.log(set); // Set(2) {1, 3}
// 清空集合
set.clear();
console.log(set); // Set(0) {}
檢查元素
因爲集合並沒有排序的概念,所以集合對象並沒有像數組對象那樣有 indexOf 方法,也就意味着不能通過 set.indexOf(value) >= 0 的形式來檢查元素是否存在於集合中。但集合對象提供了 has 方法用於檢查某集合中是否包含某一個元素。
const set = new Set([1, 2, 3, 4]);
//檢查元素
set.has(2); // true
set.has(5); // false
遍歷元素
forEach
集合對象的 forEach 方法和數組類型的一樣,傳入一個回調函數以接受集合內的元素,並且可以爲這個回調函數指定一個上下文,同樣的,集合對象的 forEach 方法也是無法被中斷的。
setObj.forEach(callbackfn[, thisArg])
- setObj: 必需。Set 對象。
- callbackfn: 必需。callbackfn 最多接受三個參數。對於集合中的每個元素,forEach 都會調用函數一次。
- thisArg:可選。可在 callbackfn 函數中爲其引用 this 關鍵字的對象。如果省略 thisArg,則 undefined 將用作 this 值。
注意無法爲箭頭函數指定一個上下文。
function callbackfn(value, key, setObj)
回調參數 | 定義 |
---|---|
Value | 集中包含的值 |
key | 集中包含的值。一組沒有鍵,因此此值與 value 相同 |
setObj | 要遍歷的 Set 對象 |
const set = new Set([1, 2, 3, 4]);
set.forEach(item => {
console.log(item);
});
// 1
// 2
// 3
// 4
set.forEach(function(item){
console.log(item * this.foo);
}, {foo: 2});
// 2
// 4
// 6
// 8
for-of
for-of 循環語句可以迭代可迭代對象(Iterable Object),並可以配合 const 和 let 使用,從而解決 forEach 方法不可中斷的問題。
const set = new Set([1, 2, 3, 4]);
for(const val of set){
console.log(val);
}
// 1 2 3
WeakSet
const weakset = new WeakSet();
weakset.add(1); // Uncaught TypeError: Invalid value used in weak set
weakset.add({foo: 1});
console.log(weakset); // WeakSet {}
console.log(weakset.size); // undefined
WeakSet 與 Set 不同的地方:
- WeakSet 不能包含值類型元素,否則會拋出一個 TypeError。
- WeakSet 不能包含無引用的對象,否則會自動清除出集合。
- WeakSet 無法被探知其大小,也無法被探知其中所包含的元素。
const weakset = new WeakSet();
let foo = {bar: 1};
weakset.add(foo);
console.log(weakset.has(foo)); // true
foo = null;
console.log(weakset.has(foo)); // false
實現將字符串等值類型加入到 WeakSet 數據結構中:
var ws = new WeakSet();
var str = new String("Hello");
var num = new Number(1);
ws.add(str);
ws.add(num);
console.log(ws.has(str)); // true
console.log(ws.has(num)); // true
這種做法的弊端在於,被加入到 WeakSet 中的字符串和數字等不能被修改,因爲一旦進行修改其引用便會丟失,甚至導致被移除出集合。
str += "hehe";
console.log(ws.has(str)); // false
WeakSet 最大的實用意義在於,可以讓我們直接對引擎中垃圾收集器的運行情況有程序化的探知方式,開發者可以利用 WeakSet 的特性以更高的定製化方案來優化程序的內存使用方案。
Map映射類型
用法:new Map([iterable]) : Map
const map = new Map();
在創建映射對象時,可以將一個以二元數組(鍵值對)作爲元素的數組傳入到構建函數中,其中每一個鍵值對都會加入到該映射對象中。該數組內的元素會以數組順序進行處理,如果存在相同的鍵,則會按照先進先出(FIFO)原則,以該鍵最後一個處理的對應值爲最終值。
const map = new Map([['foo', 1], ['foo', 2]]);
console.log(map.get('foo')); // 2
操作方法 | 方法內容 |
---|---|
set(key, value) | 添加鍵值對到映射中 |
get(key) | 獲取映射中某一個鍵的對應值 |
delete(key) | 將某一鍵值對移除出映射中 |
clear() | 清空映射中所有的鍵值對 |
entries() | 返回一個以二元數組(鍵值對)作爲元素的數組 |
has(key) | 檢查映射中是否包含某一鍵值對 |
keys() | 返回一個一當前映射中所有鍵作爲元素的可迭代對象 |
values() | 返回一個一當前映射中所有值作爲元素的可迭代對象 |
map.size | 映射中鍵值對的數量 |
映射對象 Map | 普通對象 Object | |
---|---|---|
存儲鍵值對 | √ | √ |
對遍歷所有鍵值 | √ | √ |
檢查是否包含指定鍵值對 | √ | √ |
使用字符串(String)作爲鍵 | √ | √ |
使用 Symbol 作爲鍵 | √ | √ |
使用任意對象作爲鍵 | √ | |
可以方便地得知鍵值對的數量 | √ |
除了語法和實現層面上的區別之外,映射對象和普通對象的區別還體現在 JSON 的序列化結果中。Object 的 JSON 序列化結果是標準的對象字面量形式,而 Map 的 JSON 序列化結果是以關聯數組的形式表達。
const map = new Map();
map.set('foo', 1);
map.set('bar', 2);
const str = JSON.stringify(map);
console.log(str); // [["foo",1],["bar",2]]
// ...data transport
const otherMap = new Map(JSON.parse(str));
console.log(otherMap.get('bar')); // 2
WeakMap
和 WeakSet 類似,只不過 WeakMap 的鍵會檢查變量引用,只要其中一個引用全被解除,該鍵值對就會被刪除。
const weakmap = new WeakMap();
let keyObject = {id: 1};
const valObject = {score: 100};
weakmap.set(keyObject, valObject);
weakmap.get(keyObject); // {score: 100}
keyObject = null;
console.log(weakmap.has(keyObject)); // false