javascript新增加的数据结构: Set Map WeakSet WeakMap
一、Set
ES6提供新的数据结构Set,类似于Array,不过Array中的值可以重复,但是Set中的值不可以重复
声明: Set函数是一个构造函数
let set = new Set([1,2,3,2])
console.log((new Set([1,2,3,2])).size) // 3
console.log((new Set([NaN, NaN])).size) // 1
console.log((new Set([{}, {}])).size) // 2
console.log((new Set([{a: 'a'}, {a: 'a'}])).size) //2
a = {a: 'a'}
console.log((new Set([a, a])).size) // 1
b = {a: 'a'}
console.log((new Set([a, b])).size) //2
Set数据结构判断相等的方式与===类似,但是优化了NaN的判断(这里可以原来判断NaN)
Set数据结构的属性:
Set.prototype.constructor: 构造函数,默认为Set函数,new Set([1]).constructor === Set // true
Set.prototype.size: 返回Set实例的成员总数。
Set数据结构的方法
1 interface Set<T> { 2 add(value: T): this; // 增加值,返回Set实例本身,可以连调 new Set().add({}).add({}) 3 clear(): void; // 清除所有值 4 delete(value: T): boolean; // 删除值,删除成功返回true 5 forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: any): void; // 遍历Set,接受回调函数和this对象,回调函数的参数有3个,值,键,set本身,Set数据结构中没有键,所以键===值, 6 has(value: T): boolean; // value是否在Set中 7 readonly size: number; // 返回Set的成员数量 8 }
因为Set是实现了遍历器接口,所以有如下方法
keys 返回键组成的遍历器
values 返回值组成的遍历器
entries 返回键值对组成的遍历器
Set与数组的区别
Array Set都实现了遍历器
Array中的值可以重复,但是Set中的值不可以重复
Array中有键(0,1,2),遍历可以使用arr[0]
Set中只有值,没有键,遍历可以使用forEach, for of
Set的遍历
可以直接使用for of进行遍历
Set的应用
1 // 数组去重复(基本数据类型) 2 console.log(Array.from(new Set([1,2,1]))) // [1, 2] 3 console.log([...new Set([1,2,1])]) // [1, 2] 4 5 a = [1, 2, 3] 6 b = [4, 3, 2] 7 // 数组并集 8 console.log([...new Set([...a, ...b])]) // [ 1, 2, 3, 4 ]
二、WeakSet
与Set的区别:
- WeakSet中的成员只能是对象,Set可以是任何类型
- WeakSet中的对象都是弱引用。垃圾回收是不会考虑对象在不在WeakSet中,所以WeakSet是不可引用的,是不能遍历的
添加进WeakSet的元素对象,WeakSet不会对元素对像的引用计数加1,对于被添加进WeakSet的元素对象,只要该元素对象没有被除WeakSet以外的其他对象引用,就会被垃圾回收释放,在WeakSet中的该元素对象自动被释放,不会出现内存泄漏。
1 var ws = new WeakSet(); 2 var foo = {}; 3 ws.add(foo); 4 console.log(ws.has(foo)) // true 5 ws.delete(foo); 6 console.log(ws.has(foo)) //false
interface WeakSet<T extends object> { add(value: T): this; delete(value: T): boolean; has(value: T): boolean; }
WeakSet的一个用法是存触DOM节点,而不用担心这些节点从文档移除时发生内存泄露。
1 class Foo { 2 constructor() { 3 ws.add(this); 4 } 5 method() { 6 if(!ws.has(this)) { 7 throw new TypeError('method只能在实例中使用') 8 } 9 } 10 }
保证Foo的实例方法只能在Foo的实例上调用。
三、Map
Object是字符串-值结构,它的键必须是字符串。
Map是值-值,它的键可以是任何类型的。
如果需要键值对的数据结构,Map更加合适。
let a = new Map([['name', 'wt'], ['age', 25]]) 构造函数,接受数组作为参数
interface Map<K, V> { clear(): void; delete(key: K): boolean; forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void; get(key: K): V | undefined; has(key: K): boolean; set(key: K, value: V): this; readonly size: number; }
四、WeakMap
WeakMap与Map基本相同,不过WeakMap的键必须是对象,并且是对象的弱引用。(垃圾回收机制不考虑是否在WeakMap中)
WeakMap专门用来在它的键对应的对象可能在将来会消失。有助于防止内存泄露。
1 let a = ['name', 'wt'] 2 let m = new Map().set(a, 'mmm') 3 console.log(m.get(a)) // mmm 4 a = null; 5 console.log(m.get(a)) // undefined
参考:《ES6标准入门》