首先,我们先介绍一下集合。 集合是由一组无序且唯一(即不能重复)的项组成的。 我们可以把集合想象成一个既没有重复元素,也没有顺序概念的数组。 接下来,我们基于上面的定义来创建Set类:
function Set () {
var items = {};
}
当然,我们还需要声明一些集合可用的方法。
- add(value):向集合中添加一个新的项。
- remove(value):从集合中移除一个值。
- has(value):判断集合中是否有对应值。
- clear():移除集合中所有项。
- size():返回集合所包含元素的数量。
- values():返回一个包含集合中所有值的数组。
has(value)方法
我们先来实现has(value)方法,因为后面方法的实现需要调用它。
this.has = function (value) {
return value in items;
};
因为我们使用对象来存储集合的值,所以这里就直接可以使用JavaScript的in操作符来进行判断。 当然,我们还有更好的实现方式:
this.has = function (value) {
return items.hasOwnProperty(value);
};
所有JavaScript对象都有hasOwnProperty方法,它返回一个表明对象是否具有特定属性的布尔值。 注:hasOwnProperty方法可用于判断对应属性是否属于对象本身,能把对象原型链上属性排除。
add方法
this.add = function (value) {
//检查value是否在集合中
if (!this.has(value)) {
items[value] = value;
return true;
}
return false;
};
remove方法
this.remove = function (value) {
if (this.has(value)) {
delete items[value];
return true;
}
return false;
};
clear方法
this.clear = function () {
items = {};
};
size方法
这里我们实现size方法(返回集合中有多少项)有三种方式。
第一种是在内部使用length变量,每当调用add或remove方法时对它进行操作,size方法对length进行返回。
this.size = function () {
return Object.keys(items).length;
};
这里我们使用Object类的内建函数key方法,它返回一个包含给定对象所有属性的数组,然后我们通过返回数组的length属性来实现size方法。
第三种
this.sizeLegacy = function () {
var count = 0;
for (var prop in items) {
if (items.hasOwnProperty(prop)) {
++count;
}
}
return count;
};
这里我们手动提取items对象的每一个属性,记录属性个数并返回这个数字。这个方法可以在任何浏览器上运行。
values方法
this.values = function () {
return Object.keys(items);
};
如果要想它在任意浏览器运行,可以使用下面代码:
this.valuesLegacy = function () {
var keys = [];
for (var key in items) {
if (items.hasOwnProperty(key)) {
keys.push(key);
}
}
return keys;
};
然后,我们来实现Set类一些集合的操作。
并集
对于给定的两个集合,返回一个包含两个集合中所有元素的新集合。 在数学中,集合A和集合B的并集,表示为A ∪ B。 A∪B = {x∣x∈A∨x∈B} 即x元素存在于集合A中,或x存在于集合B中。
this.union = function (otherSet) {
var unionSet = new Set();
var values = this.values();
for (var i = 0; i < values.length; i++) {
unionSet.add(values[i]);
}
values = otherSet.values();
for (var i = 0; i < values.length; i++) {
unionSet.add(values[i]);
}
return unionSet;
};
创建一个新的集合,代表两个集合的并集。然后把两集合中的值遍历添加到新的集合中。
交集
集合A和集合B的交集,表示为A∩B: A∩B = {x∣x∈A∧x∈B} 元素x存在于A中,且元素x存在于B中。this.intersection = function (otherSet) {
var intersectionSet = new Set();
var values = this.values();
for (var i = 0; i < values.length; i++) {
if (otherSet.has(values[i])) {
intersectionSet.add(values[i]);
}
}
return intersectionSet;
};
创建一个新的Set实例,遍历当前Set实例所有的值,验证对应值是否同时存在于另一个Set实例中,如果是,将其添加到新创建的Set实例中,最后将其返回。
差集
集合A和集合B的差集,表示为A-B: A-B = {x∣x∈A∧x∉B} 元素x存在于集合A中,且x不存在于集合B中。
this.difference = function () {
var differenceSet = new Set();
var values = this.values();
for (var i = 0; i < values.length; i++) {
if (!otherSet.has(values[i])) { //只获取不存在于otherSet实例中的值
differenceSet.add(values[i]);
}
}
return differenceSet;
};
子集
集合A是集合B的子集,表示为A⊆B: ∀x{x∈A→x∈B} 集合A中的每一个x元素,也在集合B中。
this.subset = function (otherSet) {
if (this.size() > otherSet.size()) {
return false;
}else {
var values = this.values();
for (var i = 0; i < values.length; i++) {
if (!otherSet.has(values[i])) {
return false;
}
}
return true;
}
};
首先验证当前Set实例中元素个数是否小于otherSet实例中元素个数。 接下来遍历当前Set实例中元素是否也都存在于otherSet实例中。
现在,我们实现了类似于ECMAScript 6中的Set类。 如果你有什么好的想法或是意见请写在下方评论区,也可以私信我。 我也会对这篇博文随时间进行修正。