天天都用數組,有沒有過一個Moment,擔憂插入了重複的值?使用Set集合吧!Set擁有特殊的數據結構,保證插入的值永遠不會重複。javascript
Set.prototype.constructor
構造函數建立Set實例/* * 僅實例化:調用構造函數,不傳參數 */
let empty_set = new Set()
/* * 實例化同時初始化:傳入任意iterate對象,將其轉換成Set集合 */
let transfer_set4arr = new Set([1, 2, 3])
// 返回Set(3) {1, 2, 3}
let transfer_set4string = new Set("huilin")
// 返回Set(5) {"h", "u", "i", "l", "n"}
let transfer_set4set = new Set(new Set([5, 6]))
// 返回Set(2) { 5, 6 }
複製代碼
Set.prototype.size
屬性,返回集合中元素的個數console.log(empty_set.size) // 0
console.log(transfer_set4arr.size) // 3
複製代碼
Set.prototype.has(value)
方法,判斷元素是否存在// 相比起Array.includes(),Set.has()性能更高,由於專門對成員測試進行了優化
console.log(empty_set.has(1)) // false
console.log(transfer_set4arr.has('h')) // true
複製代碼
Object.is(value1,value2)
進行判斷,而不是經過===(恆等符號)
符號來判斷的,由於恆等判斷會將兩邊的變量進行強制類型轉換。NaN
,或者0
和-0
,用JS判斷是不相等的,但Object.is()
認爲是同一個只,所以不能存入Set集合中。想了解更多關於
Object.is()
,請跳轉查看:developer.mozilla.org/zh-CN/docs/…java
let n1 = NaN
let n2 = NaN
console.log(n1 === n2)
// 恆等符號判斷二者不一致,輸出false
console.log(Object.is(n1,n2))
// 但Object.is()判斷二者是相同的,輸出false
// Set集合不容許將兩個NaN放入集合
let set = new Set()
set.add(n1).add(n2)
console.log(set.size)
// size: 1
複製代碼
let same_value_set = new Set();
// 先存入一個對象
same_value_set.add({num: 0});
// 再存入一個結構一致的新對象
let obj = {num: 0};
same_value_set.add(obj);
// 都能存入成功
console.log(same_value_set.size); // 2
複製代碼
Set.prototype.add(value)
方法,向集合追加數據// add()方法能夠追加任意類型的數據,不管是原始值或者是對象引用
let set1 = new Set()
// 因爲add()方法始終返回當前實例的引用,因此進行鏈式調用
set1.add(1).add(2).add(3)
console.log(set1) // Set(3) {1, 2, 3}
// 注意:當add()傳入數組時,Set會將數組實例插入集合,而不是數組內的元素
set1.add([4, 5])
console.log(set1) // Set(4) {1, 2, 3, [4, 5]}
複製代碼
Set.prototype.delete(value)
方法,移除集合中的元素// delete()方法返回移除操做是否成功,與.has()方法同樣
let success = set1.delete(1)
console.log(success)
// true
複製代碼
Set.prototype.clear()
方法,清空集合let num_set = new Set([1, 6, 3])
console.log(num_set)
// Set(3) { 1, 6, 3 }
set1.clear()
console.log(num_set)
// Set(0) {}
複製代碼
let set = new Set([1, 2, 3, 4, 5])
for(let item of set){
console.log(item)
}
// 依次輸出:1 2 3 4 5
複製代碼
/* * 建立迭代器的有三種方式 * Set.prototype.entries() * Set.prototype.keys() * Set.prototype.values() */
// Set集合只有value而沒有key,但爲了使得和遍歷Map對象類似,Set.entries()建立新的Iterator對象時,每一項的鍵和值都相等,即[value,value]
for(let [key,value] of set.entries()){
console.log(value)
}
// 依次輸出:1 2 3 4 5
// Set.keys()建立新的Iterator對象,返回每一項值
for(let key of set.keys()){
console.log(key)
}
// 依次輸出:1 2 3 4 5
// Set.values()和Set.keys()一致,返回每一項的值
for(let value of set.values()){
console.log(value)
}
// 依次輸出:1 2 3 4 5
複製代碼
Set.prototype.forEach(callbackFn)
方法遍歷// forEach(callbackFn) 按照插入順序調用callbackFn,取出每項值
set.forEach(item => {
console.log(item)
})
// 依次輸出:1 2 3 4 5
複製代碼
/* * Set轉Array */
let set1 = new Set([1, 2, 3])
// Array.from()方法
let arr1 = Array.from(set1)
// 擴展運算符
let arr2 = [...set1]
/* * Array轉Set */
// 利用Set構造函數
let set = new Set(array)
複製代碼
let set = new Set([1, 2, 4, 4, 2, 5])
console.log(set)
// Set(4) { 1, 2, 4, 5 }
複製代碼
let arr1 = [1, 2, 4]
let arr2 = [1, 5, 6]
// 利用Set集合的特性,集合內的元素都是惟一的
let result = new Set([...set1, ...set2])
console.log(result)
// Set(5) { 1, 2, 4, 5, 6 }
複製代碼
let set1 = new Set([1, 2, 4])
let set2 = new Set([1, 5, 6])
// 返回set1和set2都存在的元素
let result = new Set([...set1].filter(x => set2.has(x)))
console.log(result)
// Set(1) { 1 }
複製代碼
let set1 = new Set([1, 2, 4])
let set2 = new Set([1, 5, 6])
function isMixed(set, subset) {
for (let elem of subset) {
if (set.has(elem)) {
return true;
}
}
return false;
}
console.log(isMixed(set1, set2))
// true
複製代碼
let set1 = new Set([1, 2, 4])
let set2 = new Set([1, 5, 6])
function difference(setA, setB) {
let result = new Set()
for (let elem of setB) {
if(setA.has(elem)){
result.add(elem)
}
}
return result;
}
console.log(difference(set1, set2))
複製代碼
除了Set集合外,ES6還提供了WeakSet和WeakMap。既然集合的名字都叫「Weak(弱)的集合」了,究竟它「弱」在哪裏呢?es6
let val1 = {id: 1},
val2 = {id: 2}
let ws = new WeakSet()
// 和Set集合同樣,WeakSet的值也不重複,同時add()也返回集合實例,因此能夠鏈式操做
ws.add(val1).add(val1).add(val2)
// 不容許插入基礎數據類型
ws.add(3)
// 報錯:TypeError:Invalid value used in WeakSet
// 但能夠先包裝成對象後再插入
let val3 = new Number(3)
ws.add(val3)
console.log(ws.has(val3))
// 輸出:true
複製代碼
add()
、has()
、delete()
三個操做方法;要說弱引用,先看看什麼是強引用:數組
// 聲明一個對象
let handsome = {
name: 'huilin',
age: 30
}
// 放入數組
let arr = [1, handsome, 2]
console.log('release before arr length', arr.length) // 3
// 放入Map
let user = {
oid: 10001,
classify: 'Chinese',
staffReference: handsome
}
console.log('release before map length', Object.keys(user).length) // 3
console.log('----')
// 忽然把對象置爲null
handsome = null
// 強引用的容器中,對象仍然存在沒有被回收
console.log('release after arr length', arr.length) // 3
console.log(arr[1]) // { name: 'huilin', age: 30 }
console.log('release after map length', Object.keys(user).length) // 3
console.log(user.staffReference) // { name: 'huilin', age: 30 }
複製代碼
從測試代碼看出,除非容器銷燬,不然引用的對象一直沒有被回收。而所謂弱引用,就是但願容器是根據元素自動伸縮的,一旦對象爲null,容器中的引用也跟着回收。markdown
let obj1 = {
name: 'huilin',
age: 30
}
let obj2 = {
name: 'cc',
age: 29
}
let ws1 = new WeakSet()
ws1.add(obj1).add(obj2)
console.log(ws1.has(obj1)) // true
// 無論是從容器操做元素
ws1.delete(obj1)
console.log(ws1.has(obj1)) // false
// 或者是對象本身置爲null,都會自動回收
obj2 = null
console.log(ws1.has(obj2)) // false
複製代碼