第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

ES6-10 入門教程

ES6+ Map

1. 前言

前面兩節(jié)我們學(xué)習(xí)了 Set 的相關(guān)內(nèi)容,本節(jié)我們開始學(xué)習(xí) Map 數(shù)據(jù)結(jié)構(gòu)的內(nèi)容。Map 對(duì)象和原生的 Object 類似都是存儲(chǔ)數(shù)據(jù)的,而且也推薦使用 Map 的方式來存儲(chǔ)數(shù)據(jù)。

在 ES5 中使用 Object 來存儲(chǔ)對(duì)象,然而這種存儲(chǔ)存在一些問題,比如說 Object 中的鍵是無序的,Object 的鍵只能是字符串類型等等。ES6 提供了 Map 數(shù)據(jù)結(jié)構(gòu),保存的是鍵值對(duì),而且能夠記住鍵的插入順序,并且任何值 (對(duì)象或者原始值) 都可以作為一個(gè)鍵或一個(gè)值,這樣極大地?cái)U(kuò)展了數(shù)據(jù)存儲(chǔ)的場(chǎng)景。

2. Map 使用詳情

2.1 Map 基本說明

在前面的 數(shù)據(jù)結(jié)構(gòu)擴(kuò)展 一節(jié)我們已經(jīng)了解到 Map 的基本使用。和 Set 一樣,Map 也是一個(gè)構(gòu)造函數(shù),不能直接使用,需要通過 new 的方式來創(chuàng)建一個(gè) Map 實(shí)例。

var map = Map([iterable]);

Map 對(duì)象在插入數(shù)據(jù)時(shí)是按照順序來插入的,也就是說在插入時(shí)會(huì)保持插入的位置,Object 的在插入數(shù)據(jù)時(shí)沒有順序概念。Map 對(duì)象可以被 for...of 循環(huán),在每次迭代后會(huì)返回一個(gè)形式為 [key,value] 的數(shù)組,這個(gè)我們?cè)谙旅娴睦又袝?huì)說到。

Map 的本質(zhì)其實(shí)還是一個(gè)對(duì)象,并且它也是繼承 Object 的,看下面的實(shí)例:

var map = new Map([["x", 1], ["y", 2]]);
console.log(map instanceof Object);   //true

從上面的代碼中可以看出 Object 在實(shí)例 map 的原型鏈上。

在創(chuàng)建 Map 實(shí)例時(shí)可以接收一個(gè)數(shù)組或是一個(gè)可遍歷的對(duì)象作為參數(shù),這個(gè)參數(shù)內(nèi)的每一項(xiàng)是鍵值的組合 [key, value] 第一個(gè)值時(shí)鍵,第二個(gè)值時(shí)鍵的值。

在初始化 Map 對(duì)象時(shí),如果默認(rèn)參數(shù)的數(shù)組中超過兩個(gè)以上的值不會(huì)被 Map 對(duì)象讀取。

var map = new Map([["x", 1, 'a', 'b'], ["y", 2, 'c'], ["z", 3, 'd']]);
console.log(map)  // Map(3) {"x" => 1, "y" => 2, "z" => 3}

上面的代碼中,從打印的結(jié)果可以看出,數(shù)組中超過的元素都會(huì)被自動(dòng)忽略。

2.2 Map 的屬性和方法

Map 提供的屬性和方法從增、刪、改、查幾個(gè)方面入手,主要有以下 5 種:

方法名 描述
set 接收鍵值對(duì),向 Map 實(shí)例中添加元素
get 傳入指定的 key 獲取 Map 實(shí)例上的值
delete 傳入指定的 key 刪除 Map 實(shí)例中對(duì)應(yīng)的值
clear 清空 Map 實(shí)例
has 傳入指定的 key 查找在 Map 實(shí)例中是否存在
size 屬性,返回 Map 實(shí)例的長(zhǎng)度

Map 提供 size 屬性可以獲取 Map 實(shí)例上的長(zhǎng)度

var map = new Map([["x", 1], ["y", 2], ["z", 3]]);
console.log(map.size)  // 3

set() 方法為 Map 實(shí)例添加或更新一個(gè)指定了鍵(key)和值(value)的鍵值對(duì)。

myMap.set(key, value);

通常情況下不會(huì)一開始就初始化值,而是動(dòng)態(tài)地添加,或更新 Map 時(shí)需要用到 set 方法,可以新增和修改 Map 實(shí)例的值。而且 key 值可以是任意類型的,查看如下示例:

var map = new Map();

var str = 'string';
var obj = {};
var arr = [];
var fun = function() {};

map.set(str, '鍵的類型字符串');
map.set(obj, '鍵的類型對(duì)象');
map.set(arr, '鍵的類型數(shù)組');
map.set(fun, '鍵的類型函數(shù)');

上面的代碼中,我們定義了不同類型的變量,使用這些變量為 map 添加數(shù)據(jù)。相比 Object 對(duì)象,擴(kuò)展性更強(qiáng)了。另外還可以鏈?zhǔn)教砑渔I值對(duì):

var map = new Map();
map.set('a', 1).set('b', 2).set('c', 3);
console.log(map);   // Map(3) {"a" => 1, "b" => 2, "c" => 3}

使用鏈?zhǔn)教砑渔I值對(duì)的方式比較簡(jiǎn)潔,如果需要添加多個(gè)值,建議使用這樣的方式去添加。

get() 方法是接收一個(gè)指定的鍵(key)返回一個(gè) Map 對(duì)象中與這個(gè)指定鍵相關(guān)聯(lián)的值,如果找不到這個(gè)鍵則返回 undefined。

myMap.get(key);

使用上面的示例,可以通過 get 方法獲取對(duì)應(yīng)的值:

console.log(map.get('string'));  // "鍵的類型字符串"
console.log(map.get(str));       // "鍵的類型字符串"
console.log(map.get(obj));       // "鍵的類型對(duì)象"
console.log(map.get(arr));       // "鍵的類型數(shù)組"
console.log(map.get(fun));       // "鍵的類型數(shù)組"

上面的代碼可以看出,我們可以直接使用鍵的值去獲取 Map 實(shí)例上對(duì)應(yīng)的值,也可以通過定義變量的方式去獲取。

has() 方法是用于判斷指定的鍵是否存在,并返回一個(gè) bool 值,如果指定元素存在于 Map 中,則返回 true,否則返回 false。

myMap.has(key);

實(shí)例:

var map = new Map();
map.set("a", 11);

map.has("a");  // true
map.has("b");  // false

delete() 方法用于移除 Map 實(shí)例上的指定元素,如果 Map 對(duì)象中存在該元素,則移除它并返回 true;否則如果該元素不存在則返回 false。

myMap.delete(key);

實(shí)例:

var map = new Map();
map.set("a", 11);

map.delete("a");  // true
map.has("a");     // false

clear() 方法會(huì)移除 Map 對(duì)象中的所有元素,返回 undefined。

myMap.clear(key);

實(shí)例:

var map = new Map();
map.set("a", 11);

map.clear();  // 返回 undefined

這里需要注意的是 clear() 返回的值是 undefined 而不是 true 所以如果在判斷結(jié)果的時(shí)候需要注意這一點(diǎn)。

2.3 Map 的擴(kuò)展方法

Set 數(shù)據(jù)結(jié)構(gòu)一樣,Map 也提供了三個(gè)獲取 Map 對(duì)象的鍵值以及鍵值對(duì)組合的方法:

方法名 描述
values 返回 Map 實(shí)例中的值作為一個(gè)可以遍歷的對(duì)象
keys 返回 Map 實(shí)例中的鍵作為一個(gè)可以遍歷的對(duì)象
entries 返回 Map 實(shí)例中的鍵值對(duì)作為一個(gè)可以遍歷的對(duì)象

keys() 方法是獲取 Map 實(shí)例上的鍵,并返回一個(gè)可迭代(Iterator)的對(duì)象。

myMap.keys();
var map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);

var keys = map.keys()
console.log(keys.next().value);  // "a"
console.log(keys.next().value);  // "b"
console.log(keys.next().value);  // "c"

獲取后的 keys 結(jié)構(gòu)可以被迭代器上的 next 函數(shù)獲取到對(duì)應(yīng)值。

values() 方法是獲取 Map 實(shí)例上元素的值,并返回一個(gè)可迭代(Iterator)的對(duì)象。

myMap.values();

實(shí)例:

var map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);

var values = map.values()
console.log(values.next().value);  // 1
console.log(values.next().value);  // 2
console.log(values.next().value);  // 3

獲取后的 values 結(jié)構(gòu)可以被迭代器上的 next 函數(shù)獲取到對(duì)應(yīng)值。

entries() 方法返回一個(gè)包含 [key, value] 的可迭代(Iterator)的對(duì)象,返回的迭代器的迭代順序與 Map 實(shí)例的插入順序相同。

myMap.entries()

實(shí)例:

var map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);

var values = map.values()
console.log(values.next().value);  // 1
console.log(values.next().value);  // 2
console.log(values.next().value);  // 3

keys()、values()、entries() 都可以被 for...of 循環(huán)。

var map = new Map([["x", 1], ["y", 2], ["z", 3]]);

for (let value of map.values()) {
  console.log(value);
}
// 1
// 2
// 3

for (let [key, value] of map.entries()) {
  console.log(key + " = " + value);
}
// x = 1
// y = 2
// z = 3

注意在循環(huán) entries() 結(jié)果的時(shí)候,因?yàn)槊恳豁?xiàng)是包含鍵值的數(shù)組,可以通過 [key, value] 這種數(shù)組結(jié)構(gòu)的方式把鍵值結(jié)構(gòu)出來直接使用。

3. Map 和 Object

MapObject 有非常多的相似的地方,Map 的出現(xiàn)也是為了彌補(bǔ) Object 的不足。 Object 的鍵只能是字符串,Map 的鍵可以是任意類型的值(包括對(duì)象),所以 Map 是一種更完善的 Hash 結(jié)構(gòu)實(shí)現(xiàn)。

3.1 鍵無序問題

Object 的鍵是無序的,當(dāng)鍵可以隱式轉(zhuǎn)換為數(shù)值時(shí),在循環(huán)的時(shí)候就會(huì)被優(yōu)先排序。這也是為什么要求最好不要使用 Number 類型作為對(duì)象的屬性。

var obj = {
  c: 'C',
  3: 3,
  a: 'A',
  1: 1,
}

for (let key in obj) {
  console.log(key, obj[key])
}
// 1 1
// 3 3
// c C
// a A

Map 會(huì)記錄插入的順序,存放的是鍵值對(duì)的組合,并且不會(huì)做類型轉(zhuǎn)換。Map 可以用 forEach 循環(huán)。

var map = new Map();
map.set('c', 'C').set(3, 3).set('a', 'A').set(1, 1);
map.forEach((item, key) => {
    console.log(key, item, typeof key)
})
// c C string
// 3 3 "number"
// a A string
// 1 1 "number"

從上面的代碼中,使用 typeof 去檢查 key 的數(shù)據(jù)類型,可以看出 Map 并不會(huì)對(duì)鍵做類型轉(zhuǎn)換。

3.2 應(yīng)用場(chǎng)景

Object 不僅是存儲(chǔ)數(shù)據(jù)用的,它還可以有自己的內(nèi)部邏輯。屬性的值是一個(gè)函數(shù)時(shí),是可以被執(zhí)行的,并且可以通過 this 拿到對(duì)象上的屬性。

var obj = {
    id: 1, 
    desc: "imooc ES6 wiki", 
    print: function(){ 
        console.log(this.desc)
    }
}
console.log(obj.print()); //"imooc ES6 wiki"

所以,盡管 Map 相對(duì)于 Object 有很多優(yōu)點(diǎn),但 Object 在某些場(chǎng)景更易于使用,比如上面的實(shí)例。畢竟 Object 是 JavaScript 中最基礎(chǔ)的概念,給出使用場(chǎng)景的幾個(gè)參考。

使用 Object 的場(chǎng)景:

  1. 如果你知道所有的 key,它們都為字符串或整數(shù)(或是 Symbol 類型),而你只需要一個(gè)簡(jiǎn)單的結(jié)構(gòu)去存儲(chǔ)這些數(shù)據(jù),Object 無疑是一個(gè)非常好的選擇。另外,獲取對(duì)象的值時(shí) Object 的性能要優(yōu)于 Map;
  2. 如果需要在對(duì)象中保持自己獨(dú)有的邏輯和屬性,比如上面實(shí)例,只能使用 Object;
  3. JSON 可以直接轉(zhuǎn)為 Object,但 Map 不行。因此,在某些我們必須使用 JSON 的情況下,應(yīng)將 Object 視為首選。

使用 Map 的場(chǎng)景:

  • Map 是一個(gè)純哈希結(jié)構(gòu),使用 delete 對(duì) Object 的屬性進(jìn)行刪除操作時(shí)存在很多性能上的問題。所以,在有大量數(shù)據(jù),或是多數(shù)據(jù)進(jìn)行增、刪操作的場(chǎng)景中,使用 Map 更合適;
  • Map 會(huì)保留所有元素的插入順序。在數(shù)據(jù)迭代時(shí)不會(huì)有亂序的情況。所以,如果考慮到元素迭代或順序,使用 Map 更好;
  • Map 的鍵值可以是任意類型,而且不會(huì)做類型轉(zhuǎn)換。所以,在鍵值不確定的情況下,保證鍵值不被隱式轉(zhuǎn)換的情況下可以優(yōu)選 Map。

4. 判斷鍵值相等的問題

因?yàn)樵?Map 對(duì)象中鍵可以是任意值,所以對(duì)鍵的說明有以下幾點(diǎn):

  1. NaN 是與 NaN 相等的(雖然 NaN !== NaN),剩下所有其它的值是根據(jù) === 運(yùn)算符的結(jié)果判斷是否相等;
  2. 在目前的 ECMAScript 規(guī)范中,-0+0 被認(rèn)為是相等的,盡管這在早期的草案中并不是這樣。

5. 小結(jié)

本節(jié)我們深入地學(xué)習(xí)了 Map 的使用情況,并對(duì)比 Object 給出了幾個(gè)使用場(chǎng)景的參考。學(xué)習(xí)完本章你需要知道以下幾點(diǎn):

  • 鍵的類型可以是任意的,可以使用 function、對(duì)象等等作為 key;
  • 鍵是有順序,根據(jù)添加的順序決定的;
  • Map 是一個(gè)完善的 Hash 結(jié)構(gòu),在存放大數(shù)據(jù),或在頻繁增、刪鍵值時(shí)表現(xiàn)優(yōu)異。