JavaScript hashmap equivalent

前端 未结 17 1427
执笔经年
执笔经年 2020-11-22 13:23

As made clear in update 3 on this answer, this notation:

var hash = {};
hash[X]

does not actually hash the object X; it actually

17条回答
  •  清歌不尽
    2020-11-22 14:09

    If performance is not critical (e.g., the amount of keys is relatively small) and you don't want to pollute your (or maybe not your) objects with additional fields like _hash, _id, etc., then you can make use of the fact that Array.prototype.indexOf employs strict equality. Here is a simple implementation:

    var Dict = (function(){
        // Internet Explorer 8 and earlier does not have any Array.prototype.indexOf
        function indexOfPolyfill(val) {
          for (var i = 0, l = this.length; i < l; ++i) {
            if (this[i] === val) {
              return i;
            }
          }
          return -1;
        }
    
        function Dict(){
          this.keys = [];
          this.values = [];
          if (!this.keys.indexOf) {
            this.keys.indexOf = indexOfPolyfill;
          }
        };
    
        Dict.prototype.has = function(key){
          return this.keys.indexOf(key) != -1;
        };
    
        Dict.prototype.get = function(key, defaultValue){
          var index = this.keys.indexOf(key);
          return index == -1 ? defaultValue : this.values[index];
        };
    
        Dict.prototype.set = function(key, value){
          var index = this.keys.indexOf(key);
          if (index == -1) {
            this.keys.push(key);
            this.values.push(value);
          } else {
            var prevValue = this.values[index];
            this.values[index] = value;
            return prevValue;
          }
        };
    
        Dict.prototype.delete = function(key){
          var index = this.keys.indexOf(key);
          if (index != -1) {
            this.keys.splice(index, 1);
            return this.values.splice(index, 1)[0];
          }
        };
    
        Dict.prototype.clear = function(){
          this.keys.splice(0, this.keys.length);
          this.values.splice(0, this.values.length);
        };
    
        return Dict;
    })();
    

    Example of usage:

    var a = {}, b = {},
        c = { toString: function(){ return '1'; } },
        d = 1, s = '1', u = undefined, n = null,
        dict = new Dict();
    
    // Keys and values can be anything
    dict.set(a, 'a');
    dict.set(b, 'b');
    dict.set(c, 'c');
    dict.set(d, 'd');
    dict.set(s, 's');
    dict.set(u, 'u');
    dict.set(n, 'n');
    
    dict.get(a); // 'a'
    dict.get(b); // 'b'
    dict.get(s); // 's'
    dict.get(u); // 'u'
    dict.get(n); // 'n'
    // etc.
    

    Comparing to ECMAScript 6 WeakMap, it has two issues: O(n) search time and non-weakness (i.e., it will cause memory leak if you don't use delete or clear to release keys).

提交回复
热议问题