es6学习笔记8--Map数据结构
Map
Map結構的目的和基本用法
JavaScript的對象(Object),本質上是鍵值對的集合(Hash結構),但是只能用字符串當作鍵。這給它的使用帶來了很大的限制。
var data = {}; var element = document.getElementById("myDiv");data[element] = metadata; data["[Object HTMLDivElement]"] // metadata
上面代碼原意是將一個DOM節點作為對象data的鍵,但是由于對象只接受字符串作為鍵名,所以element被自動轉為字符串[Object HTMLDivElement]。
為了解決這個問題,ES6提供了Map數據結構。它類似于對象,也是鍵值對的集合,但是“鍵”的范圍不限于字符串,各種類型的值(包括對象)都可以當作鍵。也就是說,Object結構提供了“字符串—值”的對應,Map結構提供了“值—值”的對應,是一種更完善的Hash結構實現。如果你需要“鍵值對”的數據結構,Map比Object更合適。
var m = new Map(); var o = {p: "Hello World"};m.set(o, "content") m.get(o) // "content" m.has(o) // true m.delete(o) // true m.has(o) // false
上面代碼使用set方法,將對象o當作m的一個鍵,然后又使用get方法讀取這個鍵,接著使用delete方法刪除了這個鍵。
作為構造函數,Map也可以接受一個數組作為參數。該數組的成員是一個個表示鍵值對的數組。
var map = new Map([["name", "張三"], ["title", "Author"]]);map.size // 2 map.has("name") // true map.get("name") // "張三" map.has("title") // true map.get("title") // "Author"
上面代碼在新建Map實例時,就指定了兩個鍵name和title。
注意,只有對同一個對象的引用,Map結構才將其視為同一個鍵。這一點要非常小心。
var map = new Map();map.set(['a'], 555); map.get(['a']) // undefined
上面代碼的set和get方法,表面是針對同一個鍵,但實際上這是兩個值,內存地址是不一樣的,因此get方法無法讀取該鍵,返回undefined。
同理,同樣的值的兩個實例,在Map結構中被視為兩個鍵。
var map = new Map();var k1 = ['a']; var k2 = ['a'];map .set(k1, 111) .set(k2, 222);map.get(k1) // 111 map.get(k2) // 222
上面代碼中,變量k1和k2的值是一樣的,但是它們在Map結構中被視為兩個鍵。
由上可知,Map的鍵實際上是跟內存地址綁定的,只要內存地址不一樣,就視為兩個鍵。這就解決了同名屬性碰撞(clash)的問題,我們擴展別人的庫的時候,如果使用對象作為鍵名,就不用擔心自己的屬性與原作者的屬性同名。
如果Map的鍵是一個簡單類型的值(數字、字符串、布爾值),則只要兩個值嚴格相等,Map將其視為一個鍵,包括0和-0。另外,雖然NaN不嚴格相等于自身,但Map將其視為同一個鍵。
let map = new Map();map.set(NaN, 123); map.get(NaN) // 123 map.set(-0, 123); map.get(+0) // 123
實例的屬性和操作方法
Map結構的實例有以下屬性和操作方法。
(1)size屬性
size屬性返回Map結構的成員總數。
(2)set(key, value)
set方法設置key所對應的鍵值,然后返回整個Map結構。如果key已經有值,則鍵值會被更新,否則就新生成該鍵。
(3)get(key)
get方法讀取key對應的鍵值,如果找不到key,返回undefined。
(4)has(key)
has方法返回一個布爾值,表示某個鍵是否在Map數據結構中。
(5)delete(key)
delete方法刪除某個鍵,返回true。如果刪除失敗,返回false。
(6)clear()
clear方法清除所有成員,沒有返回值。
遍歷方法
Map原生提供三個遍歷器生成函數和一個遍歷方法。
- keys():返回鍵名的遍歷器。
- values():返回鍵值的遍歷器。
- entries():返回所有成員的遍歷器。
- forEach():遍歷Map的所有成員。
// 等同于使用map.entries() for (let [key, value] of map) {console.log(key, value); }
上面的那個例子,表示Map結構的默認遍歷器接口(Symbol.iterator屬性),就是entries方法。
map[Symbol.iterator] === map.entries // true
Map結構轉為數組結構,比較快速的方法是結合使用擴展運算符(...)。
WeakMap
WeakMap結構與Map結構基本類似,唯一的區別是它只接受對象作為鍵名(null除外),不接受其他類型的值作為鍵名,而且鍵名所指向的對象,不計入垃圾回收機制。
var 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
上面代碼中,如果將1和Symbol作為WeakMap的鍵名,都會報錯。
WeakMap的設計目的在于,鍵名是對象的弱引用(垃圾回收機制不將該引用考慮在內),所以其所對應的對象可能會被自動回收。當對象被回收后,WeakMap自動移除對應的鍵值對。典型應用是,一個對應DOM元素的WeakMap結構,當某個DOM元素被清除,其所對應的WeakMap記錄就會自動被移除。基本上,WeakMap的專用場合就是,它的鍵所對應的對象,可能會在將來消失。WeakMap結構有助于防止內存泄漏。
下面是WeakMap結構的一個例子,可以看到用法上與Map幾乎一樣。
var wm = new WeakMap(); var element = document.querySelector(".element");wm.set(element, "Original"); wm.get(element) // "Original" element.parentNode.removeChild(element); element = null; wm.get(element) // undefined
上面代碼中,變量wm是一個WeakMap實例,我們將一個DOM節點element作為鍵名,然后銷毀這個節點,element對應的鍵就自動消失了,再引用這個鍵名就返回undefined。
WeakMap與Map在API上的區別主要是兩個,一是沒有遍歷操作(即沒有key()、values()和entries()方法),也沒有size屬性;二是無法清空,即不支持clear方法。這與WeakMap的鍵不被計入引用、被垃圾回收機制忽略有關。因此,WeakMap只有四個方法可用:get()、set()、has()、delete()。
WeakMap的另一個用處是部署私有屬性。
let _counter = new WeakMap(); let _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)();}} }let c = new Countdown(2, () => console.log('DONE'));c.dec() c.dec() // DONE
上面代碼中,Countdown類的兩個內部屬性_counter和_action,是實例的弱引用,所以如果刪除實例,它們也就隨之消失,不會造成內存泄漏。
?
?
?
?
?
轉載于:https://www.cnblogs.com/huansky/p/5680573.html
總結
以上是生活随笔為你收集整理的es6学习笔记8--Map数据结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 神迹伊乐练不练
- 下一篇: JS动态改变文本中光标位置