Map 和 Set 兩數據結構在ES6的作用

現行的編程語言都會提供幾種類型的數據集合支持,在ES6 之前,JavaScript 僅提供了對數組的支持。在以數組和對象為編程主力的JavaScript 語言,ES6 中引入了4種新的數據結構,分別是:集合(Set)、弱集合(WeakSet)、映射(Map)、弱映射(WeakMap)。下面,我們看一下它們各自的表現方式吧。
一、Set [1]
1、概述
Set 對象是值的集合,可以按照插入的順序迭代它的元素。Set 中的元素只會出現一次,即 Set 中的元素是唯一的。
使用方式: new Set([ iterable ]);
參數 iterable :是一個可迭代的對象,它的所有元素將被添加到新的 Set 中。
由于 Set 中的值總是唯一的,所以需要判斷兩個值是否相等。在對象的擴展章節中,我們講到可以通過Object.is() 來判斷是否嚴格相等,在 Set 中,-0 和 +0 是兩個不同的值,NaN 和 undefined 是可以被存儲在 Set 中的,因為 NaN 在ES6中是嚴格相等的。

new Set([NaN, NaN, 2, 3, 5, 5]); // Set(4) {NaN, 2, 3, 5}

2、屬性
length 屬性:

Set.length; // 0

Set.prototype:表示 Set 構造器的原型,允許想所有 Set 對象添加新的屬性。
Set.prototype.constructor:返回實例的構造函數,默認是 Set。
Set.prototype.size:返回 Set 對象的值的個數。

var mySet1 = new Set([NaN, NaN, 2, 3, 5, 5]);
mySet1.size; // 4

3、方法
(1)、在 Set 對象尾部添加一個元素:Set.prototype.add(value)

var mySet2 = new Set([NaN, NaN, 2, 3, 5, 5]);
mySet2.add(1);
mySet2.add(1).add("undefined");
console.log(mySet2); // Set(6) {NaN, 2, 3, 5, 1,"undefined" }

(2)、清除 Set 中所有的元素:Set.prototype.clear()
(3)、判斷值是否存在于 Set 中:Set.prototype.has(value);

var mySet3 = new Set();
 mySet3.add("yuan");
 mySet3.add("monkey");
 mySet3.has("yuan"); // true
 mySet3.clear(); 
 mySet3.has("yuan"); // false

(4)、刪除 Set 中的某個值: Set.prototype.delete(value);

var mySet = new Set();
mySet.add("foo");
mySet.delete("bar"); // 返回 false,不包含 "bar" 這個元素
mySet.delete("foo"); // 返回 true,刪除成功
mySet.has("foo");    // 返回 false,"bar" 已經成功刪除

(5)遍歷 Set 對象中的元素:forEach()、keys()、values()、entries()
forEach:

function logSetElements(value1, value2, set) {
    console.log("s[" + value1 + "] = " + value2);
}
new Set(["foo", "bar", undefined]).forEach(logSetElements);
// "s[foo] = foo"
// "s[bar] = bar"
// "s[undefined] = undefined"

keys():

var mySet = new Set();
mySet.add('foo');
mySet.add('bar');
mySet.add('baz');

var setIter = mySet.keys();

console.log(setIter.next().value); // "foo"
console.log(setIter.next().value); // "bar"
console.log(setIter.next().value); // "baz"

values():

var mySet = new Set();
mySet.add('foo');
mySet.add('bar');
mySet.add('baz');

var setIter = mySet.values();

console.log(setIter.next().value); // "foo"
console.log(setIter.next().value); // "bar"
console.log(setIter.next().value); // "baz"

entries():

var mySet = new Set();
mySet.add('foo');
mySet.add('bar');
mySet.add('baz');

var setIter = mySet.entries();

console.log(setIter.next().value); // ["foo", "foo"]
console.log(setIter.next().value); // ["foo", "foo"]
console.log(setIter.next().value); //  ["baz", "baz"]

4、應用
(1)Array 與 Set 相互轉換

var myArray = ["value1", "value2", "value3"];
// 用Set構造器將Array轉換為Set
var mySet = new Set(myArray);
mySet.has("value1"); // returns true

// 用...(擴展運算符)操作符將Set轉換為Array
console.log([...mySet]); // 與myArray完全一致

(2)、數組去重

// 用數組靜態方法 Array.from
let array1 = Array.from(new Set([1, 1, 1, 2, 3, 2, 4]));
console.log(array1);
// => [1, 2, 3, 4]
// 或用擴展運算符(...)
let array2 = [...new Set([1, 1, 1, 2, 3, 2, 4])];
console.log(array2);
// => [1, 2, 3, 4]

(3)、字符串轉成 Set

var  text = "yuan";
var stringSet = new Set(text);
console.log(sringSet); // Set(4) {"y", "u", "a", "n"}
stringSet.size; //

(4)、實現并集、交集、差集

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 }

二、WeakSet[2]
1、含義
WeakSet 結構與 Set 結構類似,WeakSet 是一個構造函數,可以使用 new 命令創建 WeakSet 數據結構。

const a= ["yuan", "monkey"];
const myWeakSet = new WeakSet(a);  // WeakSet {"yuan", "monkey" }

2、與 Set 區別
(1)、WeakSet 的成員只能是對象,而不能是其他類型的值。
(2)、WeakSet 中的對象都是弱引用,即垃圾回收機制不考慮 WeakSet 對該對象的引用。
(3)、WeakSet 沒有size 屬性,沒有辦法遍歷其成員。
3、方法
(1)、WeakSet.prototype.add(value):添加新成員;
(2)、WeakSet.prototype.delete(value):清楚指定成員;
(3)、WeakSet.prototype.has(value):判斷是否存在某個成員。
三、Map[3]
1、概述
Map 對象保存鍵值對。任何值(對象或者原始值) 都可以作為一個鍵或一個值。
一個Map對象以插入順序迭代其元素 — 一個 for...of 循環為每次迭代返回一個[key,value]數組。
使用方式:new Map([iterable])
參數 iterable:可以是一個數組或者其它的 iterable 對象,其元素或為鍵值對,或為兩個元素的數組。
2、屬性
(1)、length屬性

Map.length; // 0

(2)、Map.prototype.constructor
返回一個函數,創建了實例的原型,默認是 Map 函數。
(3)Map.prototype.size
返回對象的鍵值對的數量:

var myMap = new Map();
myMap.set("a", "alpha");
myMap.set("b", "beta");
myMap.set("g", "gamma");
myMap.size; // 3

3、方法
(1)、Map.prototype.set(key, value)
設置Map對象中鍵的值。返回該Map對象。
(2)、Map.prototype.clear()
移除Map對象的所有鍵/值對 。
(3)、Map.prototype.has(key)
返回一個布爾值,表示Map實例是否包含鍵對應的值。

var myMap = new Map();
myMap.set("bar", "baz");
myMap.set(1, "foo");

myMap.size;       // 2
myMap.has("bar"); // true

myMap.clear();

myMap.size;       // 0
myMap.has("bar")  // false

(4)Map.prototype.delete(key)
移除任何與鍵相關聯的值,并且返回該值,該值在之前會被

var myMap = new Map();
myMap.set("bar", "foo");

myMap.delete("bar"); // 返回 true。成功地移除元素
myMap.has("bar");    // 返回 false。"bar" 元素將不再存在于 Map 實例中

(5)、Map.prototype.entries()
返回一個新的 Iterator 對象,它按插入順序包含了Map對象中每個元素的 [key, value] 數組。
(6)、Map.prototype.keys()
返回一個新的 Iterator對象, 它按插入順序包含了Map對象中每個元素的鍵 。
(6)、Map.prototype.values()
返回一個新的Iterator對象,它按插入順序包含了Map對象中每個元素的值

var myMap = new Map();
myMap.set("0", "foo");
myMap.set(1, "bar");
myMap.set({}, "baz");

var mapIter1 = myMap.entries();
var mapIter 2= myMap.keys();
var mapIter3 = myMap.values();

console.log(mapIter1.next().value); // ["0", "foo"]
console.log(mapIter1.next().value); // [1, "bar"]
console.log(mapIter1.next().value); // [Object, "baz"]

console.log(mapIter2.next().value); // "0"
console.log(mapIter2.next().value); // 1
console.log(mapIter2.next().value); // Object

console.log(mapIter3.next().value); // "foo"
console.log(mapIter3.next().value); // "bar"
console.log(mapIter3.next().value); // "baz"

(7)、Map.prototype.forEach(callbackFn[, thisArg])
按插入順序,為 Map對象里的每一鍵值對調用一次callbackFn函數。如果為forEach提供了thisArg,它將在每次回調中作為this值。

function logMapElements(value, key, map) {
    console.log("m[" + key + "] = " + value);
}
Map([["foo", 3], ["bar", {}], ["baz", undefined]]).forEach(logMapElements);
// logs:
// "m[foo] = 3"
// "m[bar] = [object Object]"
// "m[baz] = undefined"

(8)、Map.prototype.get(key)
返回鍵對應的值,如果不存在,則返回undefined。

var myMap = new Map();
myMap.set("bar", "foo");

myMap.get("bar");  // 返回 "foo".
myMap.get("baz");  // 返回 undefined.

4、應用
(1)、Map 與 數組之間的相互轉換

// Map 轉數組
var myMap = new Map();
myMap.set("bar", "foo");
myMap.set(1, "bar");
[...myMap]; //  [ ["bar", "foo"], [1, "bar"] ]

// 數組轉Map
const arr = new Map( [ ["bar", "foo"], [1, "bar"] ]);
console.log(arr);  // Map {"bar" => "foo", 1 => "bar"}

(2)、Map 與對象相互轉換

// Map 轉對象
function strMapToObj(strMap) {
  let obj = Object.create(null);
  for (let [k, v] of strMap) {
    obj[k] = v;
  }
  return obj;
}
 const myMap = new Map();
myMap.set("bar", "foo")
.set(1, "ooo");

strMapToObj(myMap ); // Object {1: "ooo", bar: "foo"}

// 對象轉 Map
function objToStrMap(obj) {
  let strMap = new Map();
  for (let k of Object.keys(obj)) {
    strMap.set(k, obj[k]);
  }
  return strMap;
}
objToStrMap({1: "ooo", bar: "foo"}); // Map {"1" => "ooo", "bar" => "foo"}

(3)、Map 與 JSON 相互轉換

// Map 轉 JSON
// Map 的鍵名為字符串
function strMapToJson(jsonStr) {
  return JSON.stringify(strMapToObj(jsonStr));
}
const myMap = new Map();
myMap.set("bar", "foo")
.set(1, "ooo");
strMapToJson(myMap); // "{"1":"ooo","bar":"foo"}"

// Map 的鍵名為非字符串
function mapToArrayJson(map) {
  return JSON.stringify([...map]);
}
mapToArrayJson(myMap); // "[["bar","foo"],[1,"ooo"]]"

// Json 轉 Map
// 正常情況下所有鍵名都為字符串
function jsonToStrMap(jsonStr) {
  return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap("{"1":"ooo","bar":"foo"}"); // Map {"1" => "ooo", "bar" => "foo"}

// 整個JSON 是數組
function jsonToMap(jsronStr) {
  return new Map(JSON.parse(jsronStr)); 
}
jsonToMap([["bar","foo"],[1,"ooo"]]); // Map {"1" => "ooo", "bar" => "foo"}

四、WeakMap[4]
1、含義
WeakMap 結構與 Map結構類似,也是用于生成鍵值對的集合。
2、與 Map 區別
(1)、WeakMap 只接受對象作為鍵名(null 除外),不接受其他類型的值作為鍵名。
(2)、WeakMap 的鍵名所指向的對象不計入垃圾回收機制。
(3)、沒有keys()、values()、entries() 遍歷操作。
(4)、沒有size 屬性。
(5)、不支持clear() 方法。
3、應用
(1)、以DOM 節點作為鍵名的場景應用

let myElement = document.getElementById('logo');
let myWeakmap = new WeakMap();

myWeakmap.set(myElement, {timesClicked: 0});

myElement.addEventListener('click', function() {
  let logoData = myWeakmap.get(myElement);
  logoData.timesClicked++;
}, false);

(2)、部署私有屬性

const _counter = new WeakMap();
const _action = new WeakMap();

class Countdown {
  constructor(counter, action) {
    _counter.set(this, counter);
    _action.set(this, action);
  }
  dec() {
    let counter = _counter.get(this);
    if (counter < 1) return;
    counter--;
    _counter.set(this, counter);
    if (counter === 0) {
      _action.get(this)();
    }
  }
}

const c = new Countdown(2, () => console.log('DONE'));

c.dec()
c.dec()

本章介紹了 Map 和 Set 數據結構,重點是要掌握兩個數據結構的具體代表的含義、用法以及各數據結構與Map 和 Set 之間的相互轉換。

戳我博客

章節目錄

1、ES6中啥是塊級作用域?運用在哪些地方?
2、ES6中使用解構賦值能帶給我們什么?
3、ES6字符串擴展增加了哪些?
4、ES6對正則做了哪些擴展?
5、ES6數值多了哪些擴展?
6、ES6函數擴展(箭頭函數)
7、ES6 數組給我們帶來哪些操作便利?
8、ES6 對象擴展
9、Symbol 數據類型在 ES6 中起什么作用?
10、Map 和 Set 兩數據結構在ES6的作用
11、ES6 中的Proxy 和 Reflect 到底是什么鬼?
12、從 Promise 開始踏入異步操作之旅
13、ES6 迭代器(Iterator)和 for...of循環使用方法
14、ES6 異步進階第二步:Generator 函數
15、JavaScript 異步操作進階第三步:async 函數
16、ES6 構造函數語法糖:class 類


  1. Set ?

  2. WeakSet ?

  3. Map ?

  4. WeakMap ?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,786評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,986評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,204評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,964評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,354評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,554評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,106評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,918評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,093評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,342評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,755評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,009評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,839評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,107評論 2 375

推薦閱讀更多精彩內容