JavaScript实现的HashTable(键值对)类 - 明小筑
引言
在后端语言中存在HashTable数据结构,他可以以一种key/value的形式保存数据,同时也可以通过key快速获取value的值。这是一种很便捷也很常用的功能。
原生JS中同样也没有实现HashTable的数据类型(注意是类型,并不是结构),有与它类似的数据结构——Object,JS的Object其实本质上就是一种key/value的形式,他可以看做是一种HashTable的数据结构。
下面,我会用到Object的特性来实现HashTable这种数据类型。
实现
//trim方法借鉴jQueryvar whitespace = "[\\x20\\t\\r\\n\\f]", rtrim = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g");//直接在string的原型上做了扩展String.prototype.trim = String.prototype.trim || function () { return this.treplace(rtrim, "");};//HashTable实现function HashTable() { var self = this, hash = {}, count = 0, keys = [], values = []; self.checkKey = function (key) { if ((typeof key === "string" && key.trim !== "") || typeof key === "number" || typeof key === "boolean") {return key; } else {/*本来想实现一个key也可以是复杂类型(如Object)的了,但是考虑下,实际开发中,复杂类型当做key的情况并不多,而且如果实现,可能会影响现在这种利用object特性快速取值的方式,影响性能;故限制key采取必须是基本类型的方式。*/throw new Error("Key必须是一个存在值的基本类型,并且值不可为空"); } }; self.add = function (key, value) { key = this.checkKey(key); hash[key] = value;//保证key唯一,重复key,value会被覆盖 count++; if (keys.indexOf(key) == -1) {keys.push(key); } if (values.indexOf(value) == -1) {values.push(value); } return self; }; self.remove = function (key) { key = this.checkKey(key); if (hash.hasOwnProperty(key)) {var value = hash[key];delete hash[key];count--;if (count < 0) { count = 0;}var kIndex = keys.indexOf(key), vIndex = values.indexOf(value);if (kIndex != -1) { keys.splice(kIndex, 1);}if (vIndex != -1) { values.splice(vIndex, 1);} } return self; }; self.clear = function () { for (var i = 0; i < keys.length; i++) {if (hash.hasOwnProperty(keys[i])) { delete hash[keys[i]];} } keys.splice(0, keys.length); values.splice(0, values.length); return self; }; self.count = function () { return count; }; self.contains = function (key) { return keys.indexOf(key) !== -1;; }; self.containsKey = function (key) { return keys.indexOf(key) !== -1; }; self.containsValue = function (value) { return values.indexOf(value) !== -1; }; self.getKeys = function () { return keys.concat([]); }; self.getValues = function () { return values.concat([]); }; //根据key获取值 self.getValue = function (key) { if (hash.hasOwnProperty(key)) {return hash[key]; } }; //提供快捷遍历函数 self.each = function (fun) { if (typeof fun === "function") {for (var i = 0; i < keys.length; i++) { var key = keys[i], value = hash[key]; var stop = fun.call({ key: key, value: value }, key, value); if (stop === false) break;} } }; self.toList = function () { var result = []; for (var i = 0; i < keys.length; i++) {var key = keys[i], value = hash[key];result.push({ key: key, value: value}); } return result; };};
改进
第一版实现中,我是在add方法中,直接将key加载了HashTable这个类的实例上的,这样做的好处是:可以更接近类似的后端使用方式,如下:
var ht = new HashTable();ht.add("key1","value1");ht["key2"]="value2";ht.getValue("key2");//value2ht["key1"];//value1
这样的实现会在使用时提供更大便捷,但是数据有效性不能保证,如:如果key是HashTable实例的一个方法名,那就有可能被覆盖,方法会失灵。
所以综合考虑后,编写了正文【实现】中的代码。
如果大家有更好的实现方式也可以分享,大家一起学习~~