让我们好好了解es6的Set吧

200 阅读4分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

什么是Set?

按ECMAScript6入门的文档说法:新的数据结构,类似于数组,但是成员的值是唯一的,没有重复的值。

MDN:Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。

和数组的区别

数组是一个索引集合,数组中的数据值是按索引排序的

Set是一个键的集合,不使用索引,而是使用键对数据排序。Set中的元素按插入顺序是可迭代的,它不能包含任何重复的数据。换句话说,set中的每一项都必须是唯一的。 如果所需要的数据结构是要允许有重复项的,那么Set也没有什么用。

为什么要用Set?

可以提高代码的性能

与Array相比:

  • Set中存储的元素是唯一的,而Array中可以存储重复的元素。
  • Set是集合,不能像数组用下标取值。

怎么用?

创建

//一
const s = new Set();
//二
const set = new Set([1, 2, 3, 4, 4]);//Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。
[...set]// [1, 2, 3, 4]
//三
const set = new Set(document.querySelectorAll('div')); //类数组
//四
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x)); //add方法添加,向 Set 加入值的时候,不会发生类型转换
//五
const set = new Set('ababbc')

for (let i of s) {
  console.log(i);// 2 3 5 4
}
//上面代码通过add()方法向 Set 结构加入成员,结果表明 Set 结构不会添加重复的值。

常用属性

  • Set.prototype.size:返回Set实例的成员数量。

方法

操作方法:

  • add(value):添加某个值,返回Set结构本身。
  • delete(value):删除某个值,返回一个布尔值,true为成功删除,false为之前没有这个元素。
  • has(value):返回一个布尔值,表示参数是否为Set的成员。
  • clear():清除所有成员,没有返回值。

遍历方法:

  • keys() :返回键名的遍历器
  • values() :返回值的遍历器
  • entries() :返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员

应用

ES5写法

总所周知,数组是没有remove这个方法的。当我们需要从一个数组里面移除一个特定的元素时,我们通常会怎么写?

在es6之前,我们会这么写

function remove(array, element) {
    const index = array.indexOf(element);
    array.splice(index, 1);
}

然后我们可以这么用

const arr = ["a", "e", "i", "o", "u", "x"];
arr; //["a", "e", "i", "o", "u", "x"]

// 移除其中的“x”
remove(arr, "x");
arr; // ["a", "e", "i", "o", "u"]

// 细心的同学会发现我们前面那么写的问题,如果我们再次移除“x”的话,会发生移除最后一个元素
remove(arr, "x");
arr; // ["a", "e", "i", "o"]

当数组查找不到某元素时会返回-1,则数组的splice会从末尾往前,移除了最后一个元素,于是我们会这么写

function remove(array, element) {
    const index = array.indexOf(element);

    if (index !== -1) {
        array.splice(index, 1);
    }
}

这样的话我们就每次总是需要去检测index的值。

我们还可以用filter来写remove,这样则返回一个新的数组

function remove(array, element) {
    return array.filter(e => e !== element);
}

现在,如果我们使用Set只需要像下面这样就可以了 删除某个值,返回一个布尔值,表示删除成功。

let arr = new Set([1,2,3,4,5])
arr.delete(1) // true
arr.delete(1) // false

去除数组的重复成员

[...new Set(array)]

字符串去重

[...new Set('ababbc')].join('')
// "abc"

并集

let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
let union = new Set([...a, ...b]);
console.log("union:", union);
// union: Set(4) {1, 2, 3, 4}

交集

let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
let intersect = new Set([...a].filter(x => b.has(x)));
console.log("intersect:", intersect);
// intersect: Set(2) {2, 3}

差集

var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var difference = new Set([...a].filter(x => !b.has(x)));
console.log("difference:", difference);
// difference: Set(1) {1}

可以有多种实现的方式,下面用对象实现一个简单的Set

class Set {
	constructor() {
		this.setObj = {};
	}

	has(value) {
		return this.setObj.hasOwnProperty(value);
	}

	add(value) {
		if (!this.has(value)) {
			this.setObj[value] = value;
			return true;
		} else {
			return false;
		}
	}

	remove(value) {
		if (this.has(value)) {
			delete this.setObj[value];
			return true;
		} else {
			return false;
		}
	}

	clear() {
		this.setObj = {};
	}

	size() {
		let count = 0;
		for (let key in this.setObj) {
			if (this.setObj.hasOwnProperty(key)) {
				++count;
			}
		}
		return count;
	}

	keys() {
		let keys = [];
		for (let key in this.setObj) {
			if (this.setObj.hasOwnProperty(key)) {
				keys.push(key);
			}
		}
		return keys;
	}

	values() {
		let values = [];
		for (let value in this.setObj) {
			if (this.setObj.hasOwnProperty(value)) {
				values.push(this.setObj[value]);
			}
		}
		return values;
	}
}