computed get set 传参_ES6 的 Set 与 Map深入理解
Set 和 Map 出現之前
在 ES5 中經常用對象來模擬實現 Set 集合與 Map 集合這兩種數據結構,但這種做法帶來了一些問題:比如利用?if(obj.size)?檢查集合中是否存在某個元素的時候,預期行為是只要存在?size?就能通過 if 判斷,但如果?size = 0,那么也無法繼續執行,即使此時元素是存在的。另外,對象的鍵名只能是字符串,非字符串類型的鍵名也會通過?toString()?方法被轉換成字符串,這意味著?obj[5]?與?obj['5']?沒有區別,盡管我們本意是想創建兩個不同的鍵;甚至,當鍵名是對象的時候,不管我們操作的是哪個鍵名(obj[key1]?或者?obj[key2]),實際操作的都是?obj['[object Object]'],這是因為對象會被轉換成字符串?'[object Object]',這些都是與我們的預期不符合的。因此,ES6 推出了正式的 Set 和 Map 集合。
Set
調用?new Set()?可以創建一個 Set 集合,之后通過?add()?添加元素,size?訪問元素數量。
let set = new Set()set.add('one')
set.add('two')
set.size // 2
與 ES5 中對象模擬實現不同的是,Set 集合會對添加進來的元素調用Object.is()?檢查是否一致,由于?5?與?'5'?是不同的,所以 Set 可以同時存在這兩個元素,不會發生類型轉換(唯一的例外是?+0?和?-0,盡管?Object.is(+0,-0)?返回?false,但是 Set 集合認為這兩個是一致的);同理,也可以添加多個獨立對象,它們是不會被轉換成字符串的。
set.add(5)set.add('5')
let key1 = {}
let key2 = {}
set.add(key1)
set.add(key2)
set.size // 4
還可以用?has()?檢測是否存在某個元素,用?delete()?移除指定元素,用?clear()?清空整個 Set 集合。
另外,創建 Set 集合的時候支持傳參,我們可以使用像數組這樣的可迭代對象來初始化 Set 集合(這也是將數組轉換成 Set 集合的方法):
let set = new Set([1,2,2,3,4])set.size // 4
注意:Set 集合為了保證集合元素唯一,會對數組進行元素過濾,這一點稍后可以用來進行數組去重。
那么如何訪問集合元素呢?由于 Set 集合沒有鍵名,所以不可能像數組那樣通過數值型索引值去訪問某個元素,要訪問 Set 集合的元素,我們需要先將集合轉換成數組。這個使用展開運算符?...?來實現:
let set = new Set()set.add(1)
set.add(2)
let array = [...set]
array // [1,2]
數組轉換成集合+集合轉換成數組,就可以實現數組去重:
let array = [1,2,2,3,4,5,6,6]let anotherArray = [...new Set(array)] // [1,2,3,4,5,6]
此外,可以用?forEach()?來迭代 Set 集合中的元素,該方法的回調函數接受三個參數:value,key?以及集合本身。雖然 Set 沒有?key?鍵名,但為了與數組和Map?的?forEach()?保持一致,依然提供了?key?參數,它的值與?value?是一樣的。
Weak Set
上面的 Set 是一個強引用的集合,這指的是,如果集合中存儲著對象的引用(set.add(obj)),那么即使我們已經在集合外面清除了對該對象的引用(obj = null),集合中的引用也不受影響。為了避免造成內存泄漏,我們需要一種弱引用的集合,也就是 Weak Set。
Weak Set 只存儲對象的弱引用,所以如果把集合外面對象的最后一個強引用移除,則 Weak Set 中的引用也不復存在,這樣就避免了內存泄露的情況。此外,它還有一些特點:
- 不可以存儲原始值,否則報錯
- 不可迭代,所以不能使用?forEach(),clear()
- 不支持?size?屬性
- 不暴露諸如?keys(),values()?等迭代器
Map
相比 Set,Map 存儲的是多對鍵值對,并且鍵名和鍵值支持所有的數據類型。
調用?new Map()?可以創建一個 Map 集合,之后通過?map.set(key,value)?添加鍵值對,map.get(key)?訪問指定鍵名的鍵值。
let map = new Map()let obj = {}
map.set('name','Jack')
map.set(obj,'I am object') // 不同于對象,在 Map 中鍵名可以是對象
map.get('name') // 'Jack'
map.get(obj) // 'I am object'
map.get('unexisted key') // 訪問不存在的鍵,返回 undefined
Map 同樣也有?has(key),delete(key),clear(),size?(返回鍵值對對數)等方法和屬性。
另外,可以使用數組來初始化 Map 集合,批量添加元素。由于 Map 中的元素是鍵值對,所以傳入的數組的元素也是數組:
let map = new Map([['name','Jack'],['age',12]])map.get('name') // 'Jack'
map.get('age') // 12
map.size // 2
Map 的?forEach()?方法的回調函數也接受三個參數:value,key?以及集合本身,這和數組更為接近,只不過數組對應的第二個參數是數值型索引值。
Weak Map
類似的,Map 也有弱引用集合 Weak Map。Weak Map 的鍵名必須是對象,且保存著對象的弱引用(如果集合外面引用被清除,則集合中的引用也不復存在,且鍵值對會跟著被移除);鍵值則不一定是對象,且當鍵值是對象時,它保存的依然是強引用。也就是說,Weak Map 的弱引用是針對鍵名來說的。
Weak Map 可以用來跟蹤對象的引用,進而確保將來某一刻需要清除的對象的內存一定能夠得到釋放,不發生潛在的內存泄露。
舉例來說,現在有一個 DOM 元素,它接受用戶的輸入并將輸入的信息存儲在一個對象中,如果沒有使用 Weak Map ,那么維系?DOM 對象?與?輸入信息對象?的映射關系時就有可能產生一個新的關于 DOM 對象的強引用,而在之后清除 DOM 對象原先的強引用時,該強引用可能不會被清除,這導致對象內存實際沒有得到釋放。但是,如果使用了 Weak Map,將 DOM 對象作為鍵名,輸入信息對象作為鍵值,那么由于 Weak Map 存儲的是對象的弱引用,此時就一定能保證 DOM 對象被移除后(且集合外圍對象的最后一個強引用被清除),其內存能夠得到釋放,不會發生內存泄露的問題。
此外,Weak Map 也可以用來存儲對象實例的私有變量:
let Person = (function(name,age){let privateData = new WeakMap()
function Person(){
privateData.set(this,{name:name,age:age})
}
Person.prototype.getName = function(){
return privateData.get(this).name
}
Person.prototype.getAge = function(){
return privateData.get(this).age
}
}())
在上面的這段代碼中,存在著一個 Weak Map(privateData)用來維系多個實例與自身私有變量的映射關系。每次創建新實例的時候,都會往 privateData 這個集合中添加新的”映射條目“(privateData.set(this,{name:name,age:age}),其中,this?指的是實例),鍵名是實例,鍵值是存儲私有變量的對象。這么一來,當未來某一天刪除實例的時候,由于集合外圍的實例對象的強引用被移除,Weak Map 存儲的又是實例對象的弱引用,所以保證了實弱引用也會被垃圾回收,不存在內存泄漏的問題。簡而言之,只要實例被銷毀,相關信息也會跟著銷毀,這樣就保證了信息的私有性。
此外,Weak Map 還有一些特點:
- 不支持?size?屬性
- 不可迭代,因此不支持?forEach()?和?clear()
點個「在看」,讓更多的人也能看到這篇內容。
關注「前端人」,第一時間接收原創、精選干貨文章,讓你的技能樹加速點滿!
[關注我們,加群一起學習]
總結
以上是生活随笔為你收集整理的computed get set 传参_ES6 的 Set 与 Map深入理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sql求平均日活_杨学峰博客 | Fla
- 下一篇: pythonguitkinter组件_四