您的位置:首页 > 理论基础 > 数据结构算法

ES6中Set和Map数据结构的基本概念及应用

2017-11-24 11:15 836 查看

1. Set数据结构介绍的特点

ES6中提供了新的数据结构Set和Map。

Set类似于Array,但内部存储的数据不允许重复。该方法可接受具有Iterable接口的其他数据结构作为参数。例如:

let set=new Set([1,2,3,3]);
console.log(set);
// Set(3) {1, 2, 3}


由此我们生成了一个Set结构的数据。但需要注意,虽然NaN===NaN不成立,但Set存储数据时’认为’NaN等于自己,于是Set结构只会存储一个NaN。

let set=new Set([NaN,NaN]);
console.log(set);
// Set(1) {NaN}


但{}==={}返回false在Set中会正常应用,即

let set=new Set([{},{}]);
console.log(set);
// Set(2) {{…}, {…}}


将Set转为Array方法有2种:

(1)Set结构的数据同样可以使用可接受Iterable的扩展运算符’…’

let set=new Set([1,2,3,3]);
[...set]
// [1,2,3]


显而易见,我们可以用此方法轻松去重。

(2)Array.from()方法可将具有Iterable或ArrayLike的数据类型转为Array结构的数据

Array.from(new Set([1,2,3]))
// [1,2,3]


2. Set数据结构的属性和方法

2.1 属性 Set.prototype.constructor

作用:构造函数,默认就是Set函数

2.2 属性 Set.prototype.size

作用:返回Set大小

let set=new Set([1,2,3,3]);
set.size
// 3


2.3 方法Set.prototype.add(value)

作用:向Set数据结构中添加数据,可链式添加。

let set=new Set([1,2,3,3]);
set.add(4).add('a')
// Set(5) {1,2,3,4,'a'}


2.4 方法Set.prototype.has(value)

作用:返回一个布尔值,表示该值是否为Set的成员

let set=new Set([1,2,3,3]);
set.has(2)
// true


2.5 方法Set.prototype.delete(value)

作用:删除某个值,返回一个布尔值,表示删除是否成功

let set=new Set([1,2,3,3]);
set.delete(2)
// true
set
// Set(2) {1,3}


2.6 方法Set.prototype.clear()

作用:清除所有set中保存的数据

3. Set的遍历操作

set实例具有四个遍历的方法:keys(),values(),entries(),forEach()。

3.1 keys(),values(),entries()

keys()将set实例的所有键名作为SetIterator返回,values()将set实例的所有键值作为SetIterable返回。entries()同样返回SetIterable,在console.log时会将该实例此时的键名与键值打印出来。keys(),values(),entries()方法返回的SetIterable本质上是不同的,从打印结果就可以看出。由于Set结构数据类似于Array数据,key与value相同,因此keys()与values()返回的值完全相同,entries()返回的每个表示键值对的数组中的2个元素的数值同样相同。

let set=new Set([1,2,3,3]);
for(let i of set.keys()){
console.log(i);
}
//1
//2
//3
set.keys()
// SetIterator {1, 2, 3}

for (let i of set.entries()) {
console.log(i);
}
// ['1':'1']
// ['2':'2']
// ['3':'3']
set.entries()
// SetIterator {1, 2, 3}


由于set实例的默认遍历器生成函数是它的values()方法

Set.prototype[Symbol.iterator] === Set.prototype.values
// true


也就是说Set数据结构具有一个默认的iterator接口(该接口由它的values()方法生成的),因此可以对set实例直接进行for/of遍历,此处不再举例说明。

3.2 forEach()

类似于Array,Set结构也拥有forEach()方法,不过callback的参数与Array的不同。Array.prototype.forEach(callback(currentValue,index,array){}[,thisArg]),Set.prototype.forEach(callback(value,key){}[,thisArg]),当然了每次执行时的value与key是相同的。forEach()返回undefined,另外不会改变对象里的值。关于map、forEach的区别可以参考以下回答

同样的,Array的map与filter方法也可用于Set类型数据。不过得先转成数组形式,可以参考1中的’将Set转为Array2种方法’,注意map和filter有返回值。

4. WeakSet

WeakSet与Set类型基本一致,值得注意的是WeakSet里边存放成员的只能是对象类型,例如

let weakset=new WeakSet();
weakset.add({}); // 正确
weakset.add([]); //正确
weakset.add(1); // 错误


另外WeakSet的成员对象都采用弱引用,垃圾回收机制可以回收WeakSet引用的对象所占用的内存。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。所以WeakSet的成员不适合引用,可能会被随时清理掉。另外也不可遍历,因此也没有size属性和forEach操作。

WeakSet具有add(),deldete(),has()方法,用法与Set一致,不过传的参数都是对象类型。

5. Map数据类型

Map类型的出现是为了解决传统JavaScript对象中的键值对的键名只能是字符串,由此会带来一些不便。而Map数据类型类似于对象,也是键值对的集合,但键名可以是任何类型数据,包括Number,Object,Boolean等。

用法:

const m = new Map();
const o = {p: 'Hello World'};

m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false


在Map赋值时,若键名是Number,NaN(set时会认为NaN等于它本身)或Boolean,在多次赋同样键名的值会有替换效果。例如:

const map = new Map();
map

.set(1, 'aaa')
.set(1, 'bbb');

map.get(1) // "bbb"


若键名是字符串,则不会有此问题,因为字符串作键名会和内存地址绑定,同一字符的不同实例的内存地址不同。

const map = new Map();

const k1 = ['a'];
const k2 = ['a'];

map
.set(k1, 111)
.set(k2, 222);

map.get(k1) // 111
map.get(k2) // 222


但链式set由于指向统一内存地址,因此会有值替换效果。

const map = new Map();

map
.set('a', 'aaa')
.set('a', 'bbb');

map.get('a') // 'bbb'


Map数据结构同样有size属性,set(key,value),get(key),has(key),delete(key),clear()方法。

可以通过它的keys(),values(),entries(),或实例(等同于entries)提供的Iterable接口用for/of遍历,

const map = new Map([
['F', 'no'],
['T',  'yes'],
]);
for (let key of map.keys()) {
console.log(key);
}
// "F"
// "T"

for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"

for (let [key, value] of map) {
console.log(key, value);
}
// "F" "no"
// "T" "yes"

for (let item of map) {
console.log(item);
}
// ["F", "no"]
// ["T", "yes"]


也可以对实例直接forEach遍历。

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


——参考阮一峰《ES6入门
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  前端 es6