集合是由一组无序且唯一(即不能重复)的项组成的。这个数据结构使用了与有限集合相同的概念,但应用于计算机科学的数据结构中。
1,创建一个集合
以下是set类的骨架:
function Set(){ var items = {}; }
这里有一个非常重要的细节,我们使用对象而不是数组来表示集合(items),当然也可以用数组来实现。JS的对象不允许一个键指向两个不同的属性,也保证了集合里的元素都是唯一的。
接下来,需要声明一些集合可用的方法(我们会尝试模拟与ECMAScript6实现相同的Set类)。
add(value):向集合添加一个新的项。 remove(value):从集合移除一个值。 has(value):如果值在集合中,返回true,否则返回false。 clear():移除集合中的所有项。 size():返回集合中包含元素的数量。与数组的length属性类似。 values():返回一个包含集合中所有值的数组。1,1,has(value)方法
首先要实现的是has(value)方法。这是因为它会被add、remove等其他方法调用。下面看看它的实现:
this.has = function(value){ return value in items; }
既然我们使用对象来存储集合的值,就可以用JavaScript的in操作符来验证给定的值是否是items对象的属性。
但这个方法还有更好的实现方式,如下:
this.has = function(value){ return itmes.hasOwnProperty(value); }
所有javascript对象都有hasOwnProperty方法。这个方法返回一个表明对象是否具有特定属性的布尔值。
1.2,add方法
实现add方法:
this.add = function(value){ if(!this.has(value)){ items[value] = value; return true; } return false; }
对于给定的value,可以检查它是否存在于集合中。如果不存在,就把value添加到集合中,返回true,表示添加了这个值。如果集合中已经存在这个值,就返回false,表示没有添加它。
tips: 添加一个值时,把它同时作为键和值保存,因为这样有利于查找这个值。
1.3,remove和clear方法
下面要实现remove方法:
this.remove = function(value){ if(this.has(value)){ delete items[value]; return true; } return false; }
在remove方法中,我们会验证给定的value中是否存在于集合中。如果存在,那么就移除value,返回true;否则返回false。
既然用对象来存储集合的items对象,就可以简单地使用delete操作符从items对象中移除属性。
使用Set类的示例代码如下:
var set = new Set(); set.add(1); set.add(2);
如果想移除集合中的所有值,可以用clear方法:
this.clear = function(){ items = {}; }
要重置items对象,需要做的只是把一个空对象重新赋值给它。我们也可以迭代集合,用remove方法依次移除所有的值,但既然有更简单的方法,那样做就显得太麻烦了。
1.4,size方法
下一个要实现的是size方法(返回集合中有多少项)。这个方法有三种实现方式。
第一种方法是使用一个length变量,每当使用add或者remove方法时控制它,就像链表类一样。
第二种方法是使用js内建的Object类的一个内建函数(ECMAScript5以上版本):
this.size = function(){ return Object.keys(items).length; }
JS的Object类有一个keys方法,它返回一个包含给定对象所有属性的数组。在这种情况下,可以使用这个数组的length属性来返回items对象的属性个数。只能在IE9以上版本和其他现代浏览器上使用。
第三种方法是手动提取items对象的每一个属性,记录属性的个数并返回这个数字。这个方法可以在任何浏览器上使用,和之前的代码是等价的:
this.sizeLegacy = function(){ var count = 0; for(var prop in items){ if(items.hasOwnProperty(prop)) ++count; } return count; }
遍历items对象的所有属性,检查他们是否是对象自身的属性。如果是,就递增count变量的值,最后在方法结束时返回这个数字。
1.5,values方法
values方法也应用了相同的逻辑,提取items对象的所有属性,以数组的形式返回:
this.values = function(){ return Object.keys(items); }
以上代码只能在IE9及其他现代浏览器上使用。
如果想让代码在任何浏览器上使用,可以用与之前代码等价的下面这段代码:
this.valuesLegacy = function(){ var keys = []; for(var key in items){ keys.push(key); } return keys; }
遍历items对象的所有属性,把他们添加到一个数组中,然后返回这个数组。
1.6,使用Set类
现在数据结构已经完成了,看看如何使用它吧。
var set = new Set(); set.add(1); console.log(set.values()); //['1'] console.log(set.has(1)); //true console.log(set.size()); //1 set.add(2); console.log(set.values()); //['1','2'] console.log(set.has(2)); //true console.log(set.size()); //2 set.remove(1); console.log(set.values()); //['2'] set.remove(2); console.log(set.values()); //[]