目錄
1.Set
ES6 提供了新的數據結構 Set
。它類似於數組,但是成員的值都是唯一的,沒有重複的值。
Set
本身是一個構造函數,用來生成 Set 數據結構。
let s = new Set();
typeof s; // "object"
Set
函數可以接受一個數組(或者具有 iterable
接口的其他數據結構)作爲參數,用來初始化。
// 接受數組作爲參數
let x = new Set(["jidi", "rycony", "xuxiake2019"]);
x; // Set(3) {"jidi", "rycony", "xuxiake2019"}
// 接受具有iterable接口的數據結構作爲參數
let y = new Set("jidi");
y; // Set(3) {"j", "i", "d"}
上面代碼中,變量y
最終只有三個元素,那是因爲Set
數據結構成員的值都是唯一的。
向 Set 加入值的時候,不會發生類型轉換。Set 內部判斷兩個值是否不同,使用的算法叫做“Same-value-zero equality”。
let x = new Set();
// set內部認爲NaN等於NaN
x.add(NaN);
x.add(NaN);
x; // Set(1) {NaN}
// set添加值,不會發生類型轉換
x.add(1);
x.add("1");
x; // Set(3) {NaN, 1, "1"}
// set內部+0等於-0
x.add(+0);
x.add(-0);
x; // Set(4) {NaN, 1, "1", 0}
1.1 Set 實例的屬性和方法
Set結構的實例有以下屬性:
Set.prototype.constructor
:構造函數,默認是Set
函數。Set.prototype.size
:返回Set實例的成員總數。
let x = new Set([1, 2, 3]);
// 獲得實例構造函數,默認爲Set
x.constructor; // ƒ Set() { [native code] }
// 獲得set實例的成員數
x.size; // 3
Set結構的實例有以下方法:
操作數據相關方法:
Set.prototype.add(val)
:添加某個值,返回 Set 結構本身。Set.prototype.delete(val)
:刪除某個值,返回一個布爾值,表示刪除是否成功。Set.prototype.has(val)
:返回一個布爾值,表示該值是否爲Set的成員。Set.prototype.clear()
:清除所有成員,沒有返回值。
let x = new Set();
// 向set添加值,返回set結構
x.add("jidi");
x.add("rycony");
x; // Set(2) {"jidi", "rycony"}
// 刪除,返回布爾值,表示是否刪除成功
x.delete("jidi"); // true
x; // Set(1) {"rycony"}
// 判斷一個值是否在set中
x.has("rycony"); // true
// 清空set
x.clear();
x; // Set(0) {}
遍歷數據相關方法:
Set.prototype.keys()
:返回鍵名的遍歷器。Set.prototype.values()
:返回鍵值的遍歷器。Set.prototype.entries()
:返回鍵值對的遍歷器。Set.prototype.forEach()
:使用回調函數遍歷每個成員。
(1)keys(),values(),entries()
keys()
,values()
,entries()
三個方法返回的都是遍歷器對象。由於Set結構沒有鍵名,只有鍵值,keys()
,values()
兩個方法的行爲一致。
let x = new Set("jidi");
// 獲取鍵名
x.keys(); // SetIterator {"j", "i", "d"}
// 獲取鍵值
x.values(); // SetIterator {"j", "i", "d"}
//獲取鍵值對
x.entries(); // SetIterator {"j" => "j", "i" => "i", "d" => "d"}
Set結構的實例默認可遍歷,它的默認遍歷器生成函數就是values()
方法。
Set.prototype[Symbol.iterator] === Set.prototype.values; // true
由於Set結構實例默認遍歷器生成函數就是values()
方法,我們可以省略values()
方法,遍歷Set結構實例。
let x = new Set("jidi");
for(let m of x.values()) {
console.log(m);
}
// 等價於
for(let m of x) {
console.log(m);
}
(2) forEach()
Set 結構的實例擁有forEach
方法,用於對每個成員執行某種操作,沒有返回值。
let x = new Set([1, 2, 3, 4]);
let y = [];
x.forEach((value,key) => y.push(value * key));
y; // [1, 4, 9, 16]
上面代碼中,forEach()
方法的參數是一個函數。該函數可以接受三個參數,依次是:鍵值,鍵名,集合本身。
forEach()
方法還可以有第二個參數,用來綁定處理函數內部的this
對象。
1.2 Set 實例與擴展運算符結合使用
擴展運算符(...
)內部使用的是for ...of
循環,也可以用於Set結構實例。
let x = new Set(["jidi", "rycony", "xuxiake2016"]);
// 通過擴展運算符將Set結構實例轉爲數組
[...x]; // ["jidi", "rycony", "xuxiake2016"]
擴展運算符(...
)與Set結合使用,可以去除數組的重複成員。
let x = [1, 2, 3, 4, 3, 2];
x = [...new Set(x)]; // [1, 2, 3, 4]
通過擴展運算符,數組的map
和filter
方法也能間接被Set結構實例使用。
let x = [1, 2, 3, 4, 5, 6];
let set = new Set(x);
// 使用數組的map方法
set = new Set([...set].map(value => value + 1)); // Set(6) {2, 3, 4, 5, 6, 7}
// 使用數組的filter方法
set = new Set([...set].filter(x => x % 2 === 0 )); // Set(3) {2, 4, 6}
Set結構實例與擴展運算符結合使用,可以很容易實現並集,交集,差集。
let a = new Set([1, 2, 3, 4]);
let b = new Set([4, 3, 2, 9]);
// 並集
let x = new Set([...a, ...b]); // Set(5) {1, 2, 3, 4, 9}
// 交集
let y = new Set([...a].filter(value => b.has(value))); // Set(3) {2, 3, 4}
// 差集
let z = new Set([...a].filter(value => !b.has(value))); // Set(1) {1}
如果要在遍歷操作中,同步改變原來的 Set 結構,目前有兩種變通方法:
- 利用原 Set 結構映射出一個新的結構,然後賦值給原來的 Set 結構
- 利用
Array.from
方法,將一個類似數組的結構變爲真正的數組,作爲Set的參數
// 方法一
let set = new Set([1, 2, 3]);
set = new Set([...set].map(x => x + 1)); // Set(3) {2, 3, 4}
// 方法二
set = new Set([1, 2, 3]);
set = new Set(Array.from(set, x => x * x)); // Set(3) {1, 4, 9}
2. WeakSet
WeakSet 結構與 Set 類似,也是不重複的值的集合。但是,它與 Set 有兩個區別:
- WeakSet 的成員只能是對象,而不能是其他類型的值
- WeakSet 中的對象都是弱引用
let weakSet = new WeakSet();
// WeakSet成員只能是對象
weakSet.add(1); // Uncaught TypeError: Invalid value used in weak set at WeakSet.add
weakSet.add(true); // TypeError
weakSet.add({name: "jidi"}); // 成功添加對象
WeakSet 是一個構造函數,可以使用new
命令,創建 WeakSet 數據結構。
作爲構造函數,WeakSet 可以接受一個數組或類似數組的對象作爲參數。(具有 Iterator
接口的對象,都可以作爲 WeakSet 的參數。)該數組的所有成員,都會自動成爲 WeakSet 實例對象的成員。
let a = [[1, 2], [3, 4]];
let weakSet = new WeakSet(a); // WeakSet {[1, 2], [3, 4]}
上面代碼中,數組a
的成員也是數組,將a
作爲WeakSet的參數,a
的成員會自動成爲WeakSet實例的成員。這意味着,數組或類似數組的對象作爲參數時,其內部成員必須是對象。
let a = [1, 2];
let weakSet = new WeakSet(a); // Uncaught TypeError: Invalid value used in weak set at WeakSet.add at new WeakSet
2.1 WeakSet實例方法
WeakSet 結構有以下三個方法:
WeakSet.prototype.add(obj)
:向 WeakSet 實例添加一個新成員WeakSet.prototype.delete(obj)
:清除 WeakSet 實例的指定成員WeakSet.prototype.has(obj)
:返回一個布爾值,表示某個值是否在 WeakSet 實例之中
let x = { name: "jidi" };
let y = { name: "rycony" };
let z = { name: "xuxaike2016" };
let weakSet = new WeakSet();
// 添加成員
weakSet.add(x);
weakSet.add(y);
weakSet.add(z);
// 刪除成員
weakSet.delete(x); // true
// 判斷某個值是否在WeakSet
weakSet.has(x); // false
WeakSet 不能遍歷,是因爲成員都是弱引用,隨時可能消失,遍歷機制無法保證成員的存在。而且WeakSet 也沒有size
屬性。
3. Map
JavaScript 的對象(Object
),本質上是鍵值對的集合,但是傳統上只能用字符串當作鍵。
ES6 提供了 Map 數據結構。它類似於對象,也是鍵值對的集合,但是“鍵”的範圍不限於字符串,各種類型的值都可以當作鍵。
Map
本身是一個構造函數,用來生成 Map數據結構。
let map = new Map();
作爲構造函數,Map
也可以接受一個數組作爲參數。該數組的成員是一個個表示鍵值對的數組。
let map = new Map([
["name", "jidi"]
]);
map.size; // 1
任何具有 Iterator
接口、且每個成員都是一個雙元素的數組的數據結構都可以當作Map構造函數的參數。
let set = new Set([["name", "jidi"], ["age", 22]]);
let map = new Map(set); // Map(2) {"name" => "jidi", "age" => 22}
如果對同一個鍵多次賦值,後面的值將覆蓋前面的值。
let set = new Set([["name", "jidi"], ["name", 22]]);
let map = new Map(set); // Map(1) {"name" => 22}
如果讀取一個未知的鍵,則返回undefined
。
new Map().get("name"); // undefined
只有對同一個對象的引用,Map 結構纔將其視爲同一個鍵。
let a = { name: "jidi" };
let map = new Map();
// 鍵名爲基本數據類型
map.set("name", "jidi"); // Map(1) {"name" => "jidi"}
map.get("name"); // "jidi"
// 鍵名爲對象
map.set(a, 22);
map.get({name: "jidi"}); // undefined
map.get(a); // 22
上面代碼中,鍵名爲基本數據類型時,只要兩個值相等,則Map將其視爲一個鍵;當鍵名爲對象時,內存地址一樣纔會視爲一個鍵。
3.1 Map實例屬性和方法
Map結構實例有以下屬性:
Map.prototype.size
:返回Map實例的成員總數
new Map([[name, "jidi"]]).size; // 1
Map結構的實例有以下方法:
操作數據相關方法:
Map.prototype.set(key, value)
:設置鍵名key
對應的鍵值爲value
,然後返回整個Map
結構。如果key
已經有值,則鍵值會被更新,否則就新生成該鍵。Map.prototype.get(key)
:讀取key
對應的鍵值,如果找不到key
,返回undefined
。Map.prototype.has(key)
:返回一個布爾值,表示某個鍵是否在當前Map
對象之中。Map.prototype.delete(key)
:刪除某個鍵,刪除成功返回true
。如果刪除失敗,返回false
。Map.prototype.clear()
:清除所有成員,沒有返回值。
let map = new Map();
map.set('name', "jidi"); // 鍵是字符串
map.set(22, "age"); // 鍵是數值
map.set(undefined, ''); // 鍵是 undefined
map: // Map(3) {"name" => "jidi", 22 => "age", undefined => ""}
map.get(22); // 鍵名存在,返回鍵值"age"
map.get(23); // 鍵名不存在,返回undefined
map.has(22); // true
map.has(23); // false
map.delete(22); // 刪除成功返回true
map; // Map(2) {"name" => "jidi", undefined => ""}
map.clear(); // 清除所有成員
map; // Map(0) {}
遍歷數據相關方法:
Map.prototype.keys()
:返回鍵名的遍歷器。Map.prototype.values()
:返回鍵值的遍歷器。Map.prototype.entries()
:返回所有成員的遍歷器。Map.prototype.forEach()
:遍歷 Map 的所有成員。
let map = new Map([
["name", "jidi"],
["age", 22],
]);
// 遍歷鍵名
for (let key of map.keys()) {
console.log(key);
}
// "name" "age"
// 遍歷鍵值
for (let value of map.values()) {
console.log(value);
}
// "jidi" 22
// 遍歷鍵值對
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// "name" "jidi"
// "age" 22
// 或者
for (let [key, value] of map.entries()) {
console.log(key, value);
}
// "name" "jidi"
// "age" 22
// 等同於使用map.entries()
for (let [key, value] of map) {
console.log(key, value);
}
// "name" "jidi"
// "age" 22
上面代碼中,最後一個例子,表明Map
結構的默認遍歷器接口其實就是entries
方法。
Map[Symbol.iterator] === Map.entries; // true
4. WeakMap
WeakMap
結構與Map
結構類似,也是用於生成鍵值對的集合。但是,它與 Map
有兩個區別:
WeakMap
只接受對象作爲鍵名(null
除外),不接受其他類型的值作爲鍵名。WeakMap
的鍵名所引用的對象都是弱引用。
// WeakMap 可以使用 set 方法添加成員
let weakMap = new WeakMap();
let x = { name: "jidi"};
weakMap.set(x, 22);
weakMap.get(x); // 22
// WeakMap 也可以接受一個數組,作爲構造函數的參數
let a1 = [1, 2, 3];
let a2 = [4, 5, 6];
weakMap = new WeakMap([[a1, "jidi"], [a2, "rycony"]]);
weakMap.get(a2); // "rycony"
// 鍵名必須是對象
map = new WeakMap();
map.set(1, 2); // TypeError: 1 is not an object!
map.set(Symbol(), 2); // TypeError: Invalid value used as weak map key
map.set(null, 2); // TypeError: Invalid value used as weak map key
4.1 WeakMap實例方法
WeakMap 與 Map 在 API 上的區別主要是兩個:沒有遍歷操作;也沒有size
屬性。 因此,WeakMap只有四個方法可用:
WeakMap.prototype.get(key)
:讀取key
對應的鍵值,如果找不到key
,返回undefined
。WeakMap.prototype.has(key)
:返回一個布爾值,表示某個鍵是否在當前Map
對象之中。WeakMap.prototype.delete(key)
:刪除某個鍵,刪除成功返回true
。如果刪除失敗,返回false
。WeakMap.prototype.set(key, value)
:設置鍵名key
對應的鍵值爲value
,然後返回整個Map
結構。如果key
已經有值,則鍵值會被更新,否則就新生成該鍵。
5. 參考鏈接
本篇博文是我自己學習筆記,原文請參考:ECMAScript 6 入門
如有問題,請及時指出!
歡迎溝通交流,郵箱:[email protected]。