JavaScript >> Javascript 文檔 >  >> Tags >> map

ECMAScript 6 集合,第 2 部分:地圖

地圖 1 和集合一樣,對於那些來自其他語言的人來說也是一個熟悉的話題。基本思想是將值映射到唯一鍵,以便您可以在任何時間點使用該鍵檢索該值。在 JavaScript 中,開發人員傳統上使用常規對像作為映射。事實上,JSON 是基於對象表示鍵值對的前提。但是,影響用作集合的對象的相同限制也影響用作映射的對象:無法具有非字符串鍵。

在 ECMAScript 6 之前,您可能已經看到如下代碼:

var map = {};

// later
if (!map[key]) {
    map[key] = value;
}

此代碼使用常規對象來充當地圖,檢查給定鍵是否存在。這裡最大的限制是 key 將始終轉換為字符串。除非您想使用非字符串值作為鍵,否則這沒什麼大不了的。例如,也許您想存儲一些與特定 DOM 元素相關的數據。您可以嘗試這樣做:

// element gets converted to a string
var data = {},
    element = document.getElementById("my-div");

data[element] = metadata;

不幸的是,element 將被轉換成字符串 "[Object HTMLDivElement]" 或類似的東西(確切的值可能因瀏覽器而異)。這是有問題的,因為每個 <div> element 被轉換為相同的字符串,這意味著即使您在技術上使用不同的元素,您也會不斷地覆蓋相同的鍵。為此,Map type 是 JavaScript 的一個受歡迎的補充。

ECMAScript 6 Map type 是鍵值對的有序列表,其中鍵和值都可以是任何類型。 5 的一個鍵 不同於 "5" 的鍵 , 並且使用與集合的值相同的規則來確定鍵是否相同:NaN 被認為與 NaN 相同 , -0 不同於 +0 ,否則為 === 適用。您可以使用 set() 從地圖中存儲和檢索數據 和 get() 方法,分別:

var map = new Map();
map.set("name", "Nicholas");
map.set(document.getElementById("my-div"), { flagged: false });

// later
var name = map.get("name"),
    meta = map.get(document.getElementById("my-div"));

在此示例中,存儲了兩個鍵值對。關鍵 "name" 存儲一個字符串,而鍵 document.getElementById("my-div") 用於將元數據與 DOM 元素相關聯。如果映射中不存在鍵,則特殊值 undefined 調用get()時返回 .

Maps 與集合共享幾個方法,例如 has() 用於確定地圖中是否存在鍵和 delete() 用於從地圖中刪除鍵值對。您也可以使用 size 確定地圖中有多少項目:

var map = new Map();
map.set("name", "Nicholas");

console.log(map.has("name"));   // true
console.log(map.get("name"));   // "Nicholas"
console.log(map.size);        // 1

map.delete("name");
console.log(map.has("name"));   // false
console.log(map.get("name"));   // undefined
console.log(map.size);        // 0

如果要從地圖中刪除所有項目,則可以使用 clear() 方法:

var map = new Map();
map.set("name", "Nicholas");

console.log(map.has("name"));   // true
console.log(map.get("name"));   // "Nicholas"
console.log(map.size);        // 1

map.clear();
console.log(map.has("name"));   // false
console.log(map.get("name"));   // undefined
console.log(map.size);        // 0

為了更容易將大量數據添加到地圖中,您可以將數組數組傳遞給 Map 構造函數。在內部,每個鍵值對都存儲為一個包含兩個項目的數組,第一個是鍵,第二個是值。因此,整個地圖是這兩項數組的數組,因此可以使用該格式初始化地圖:

var map = new Map([ ["name", "Nicholas"], ["title", "Author"]]);

console.log(map.has("name"));   // true
console.log(map.get("name"));   // "Nicholas"
console.log(map.has("title"));  // true
console.log(map.get("title"));  // "Author"
console.log(map.size);        // 2

當您想要使用地圖中的所有數據時,您有多種選擇。實際上有三種生成器方法可供選擇:keys ,它遍歷地圖中的鍵,values ,它迭代地圖中的值,以及 items ,它通過返回一個包含鍵和值的數組來迭代鍵值對(items 是地圖的默認迭代器)。使用這些的最簡單方法是使用 for-of 循環:

for (let key of map.keys()) {
    console.log("Key: %s", key);
}

for (let value of map.values()) {
    console.log("Value: %s", value);
}

for (let item of map.items()) {
    console.log("Key: %s, Value: %s", item[0], item[1]);
}

// same as using map.items()
for (let item of map) {
    console.log("Key: %s, Value: %s", item[0], item[1]);
}

迭代鍵或值時,每次循環都會收到一個值。遍歷項時,會收到一個數組,其中第一項是鍵,第二項是值。

另一種迭代項目的方法是使用 forEach() 方法。此方法的工作方式類似於 forEach() 在數組上。您傳入一個使用三個參數調用的函數:值、鍵和映射本身。例如:

map.forEach(function(value, key, map)) {
    console.log("Key: %s, Value: %s", key, value);
});

也類似於 forEach() 的數組版本 , 你可以傳入一個可選的第二個參數來指定 this 在回調中使用的值:

var reporter = {
    report: function(key, value) {
        console.log("Key: %s, Value: %s", key, value);
    }
};

map.forEach(function(value, key, map) {
    this.report(key, value);
}, reporter);

這裡,this 回調函數內部的值等於 reporter .這允許 this.report() 才能正常工作。

將此與迭代值和常規對象的笨拙方式進行比較:

for (let key in object) {

    // make sure it's not from the prototype!
    if (object.hasOwnProperty(key)) {
        console.log("Key: %s, Value: %s", key, object[key]);
    }

}

當使用對像作為映射時,原型中的屬性可能會在“for-in”循環中洩漏,這始終是一個問題。你總是需要使用 `hasOwnProperty()` 來確保你只得到你想要的屬性。當然,如果對像上有方法,你也必須過濾那些:

for (let key in object) {

    // make sure it's not from the prototype or a function!
    if (object.hasOwnProperty(key) &#038;&#038; typeof object[key] !== "function") {
        console.log("Key: %s, Value: %s", key, object[key]);
    }

}

地圖的迭代功能使您可以只關注數據,而不必擔心額外的信息會滑入您的代碼中。這是 map 在存儲鍵值對方面相對於常規對象的另一大好處。

瀏覽器支持

Firefox 和 Chrome 都實現了 Map ,但是,在 Chrome 中,您需要手動啟用 ECMAScript 6 功能:轉到 chrome://flags 並啟用“實驗性 JavaScript 功能”。兩種實現都不完整。兩種瀏覽器都沒有實現任何用於 for-of 的生成器方法 並且 Chrome 的實現缺少 size() 方法(它是 ECMAScript 6 草案規範的一部分 2 ) 並且構造函數在傳遞數組數組時不會進行初始化。

總結

ECMAScript 6 映射為該語言帶來了一個非常重要且經常使用的特性。長期以來,開發人員一直想要一種可靠的方式來存儲鍵值對,並且長期以來一直依賴常規對象。 Maps 提供常規對象無法提供的所有功能,包括迭代鍵和值的簡單方法以及消除對原型的關注。

與集合一樣,地圖是尚未完成的 ECMAScript 6 草案的一部分。正因為如此,地圖仍然被認為是一個實驗性的 API,並且在規範最終確定之前可能會發生變化。所有關於 ECMAScript 6 的帖子都應該被視為即將發生的事情的預覽,而不是明確的參考。實驗性 API 雖然在某些瀏覽器中實現,但尚未準備好在生產中使用。

更新

  • 2014 年 1 月 5 日 – 更改了對 size() 的引用 size 的方法 屬性以反映規範的變化。

參考

  1. 簡單的地圖和集合(ES6 Wiki)
  2. ECMAScript 6 規範草案 (ECMA)

Tutorial JavaScript 教程
  1. 聊天框,自動滾動到底部

  2. 我怎麼知道畫布何時完成繪製?

  3. 如何通過 JavaScript 訪問 HTTP 請求標頭字段?

  4. 在開發人員心中:您如何規劃 UI 功能?

  5. 用 Project Euler 解決問題,第 1 部分:3 和 5 的倍數

  6. 當用戶懸停在滾動條上時如何增加滾動條的寬度

  7. React hooks - 使用狀態(數組)

  1. 將您的圖標與 Figma API 同步

  2. 使用 Volta 管理多個節點版本(比 nvm 更好?)

  3. 映射前端和後端的 .env 中的端口值和錯誤:無法讀取未定義的屬性錯誤(匿名函數)

  4. 使用 Node.js 自動化您的 Cognito 託管 UI 樣式流程

  5. FIREBASE 獲取文檔數據

  6. Notepad++ 的 JavaScript 自動完成

  7. 你如何在Javascript中四捨五入到小數點後一位?

  1. 面向初學者的 Vanilla JS 解構

  2. 使用 markdown-autodocs github 操作使 Markdown 自動化變得簡單

  3. 隨機字母效果:一個 jQuery 插件

  4. 快速演示!五個月的建設。