用ES5模拟实现ES6中的Set类
集合是由一组无序且唯一的项组成,ECMAScript2015(ES6)包括了Set类的实现,下面用ES5模拟实现ES6中的Set类
1.创建集合
我们用对象来实现Set类,当然也可以用数组,js对象一个键不能指向两个值,这保证了集合元素的唯一性。先初始化Set类
function Set() { var items = {}; }
1.1 has方法
this.has = function(value){ return value in items; }
用js的in操作符验证给定值是否是items对象的属性,这个方法还有更好的一个实现,那就是用js对象都有的hasOwnProperty方法
this.has = function(value){ return items.hasOwnProperty(value); }
1.2 add方法
this.add = function(value){ if (!this.has(value)) { items[value] = value; return true; } return false; }
注:添加一个值时,把它同时作为键和值保存,这样有利于查找该值
1.2 remove和clear方法
this.remove = function(value){ if (this.has(value)) { delete value; return true; } return false; }, this.clear = function(){ items={}; }
1.3 size方法
size方法的实现可以使用一个length属性,每当调用add和remove方法时动态更新其值;
也可以使用js的Object类实现
this.size = function(){ return Object.keys(items).length; }
最后一种方法是,手动统计items对象的属性数量
this.size = function(){ var count = 0; for(var prop in items){ if (items.hasOwnProperty(prop)) { ++count; } } return count; }
1.4 values方法
values方法提取items对象所有属性,以数组形式返回
this.values= function(){ var values = []; for(var value in items){ if (items.hasOwnProperty(value)) { values.push(value); } } return values; }
2.集合操作
2.1 并集
创建一个新集合代表两个集合的并集,分别变量两个集合的所有值,将他们添加到代表并集的集合中,最后返回并集。
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; }
2.2 交集
创建一个新集合代表两个集合的交集,遍历一个集合的所有值,将另一个集合中同样也含有的值,添加到代表交集的集合中,最后返回交集。
this.intersection = function(otherSet){ var intersection = new Set(); var values = this.values(); for (var i = 0; i < values.length; i++) { if (otherSet.has(values[i])) { intersection.add(values[i]); } } return intersection; }
2.3 差集
差集实现和交集类似,只不过是遍历一个集合的所有值,将另一个集合中不在这个集合中的值,添加到代表差集的集合中,最后返回差集。
this.difference = function(otherSet){ var difference = new Set(); var values = this.values(); for (var i = 0; i < values.length; i++) { if (!otherSet.has(values[i])) { difference.add(values[i]); } } return difference; }
2.4 子集
判断调用subset方法的集合是不是otherSet的子集
this.subset = function(otherSet){ var values = this.values(); if (this.size() > otherSet.size()) { return false; } else{ for (var i = 0; i < values.length; i++) { if (!otherSet.has(values[i])) { return false; } } return true; } }
下面给出完整实现的Set类
function Set() { var items = {}; // this.has = function(value){ // return value in items; // } this.has = function(value){ return items.hasOwnProperty(value); }, this.add = function(value){ if (!this.has(value)) { items[value] = value; return true; } return false; }, this.remove = function(value){ if (this.has(value)) { delete value; return true; } return false; }, this.clear = function(){ items={}; }, this.size = function(){ var count = 0; for(var prop in items){ if (items.hasOwnProperty(prop)) { ++count; } } return count; }, this.values= function(){ var values = []; for(var value in items){ if (items.hasOwnProperty(value)) { values.push(value); } } return values; }, 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; }, this.intersection = function(otherSet){ var intersection = new Set(); var values = this.values(); for (var i = 0; i < values.length; i++) { if (otherSet.has(values[i])) { intersection.add(values[i]); } } return intersection; }, this.difference = function(otherSet){ var difference = new Set(); var values = this.values(); for (var i = 0; i < values.length; i++) { if (!otherSet.has(values[i])) { difference.add(values[i]); } } return difference; }, this.subset = function(otherSet){ var values = this.values(); if (this.size() > otherSet.size()) { return false; } else{ for (var i = 0; i < values.length; i++) { if (!otherSet.has(values[i])) { return false; } } return true; } } }