我需要使用JavaScript存储一些统计数据,就像我在c#中做的那样:

Dictionary<string, int> statistics;

statistics["Foo"] = 10;
statistics["Goo"] = statistics["Goo"] + 1;
statistics.Add("Zoo", 1);

JavaScript中是否存在哈希表或Dictionary<TKey, TValue>之类的东西? 我如何以这种方式存储值呢?


当前回答

除非你有特别的理由不这样做,否则就用一个普通的对象。JavaScript中的对象属性可以使用哈希表样式的语法引用:

var hashtable = {};
hashtable.foo = "bar";
hashtable['bar'] = "foo";

foo和bar元素现在都可以被引用为:

hashtable['foo'];
hashtable['bar'];

// Or
hashtable.foo;
hashtable.bar;

当然,这意味着你的键必须是字符串。如果它们不是字符串,它们会在内部转换为字符串,所以它仍然可以工作。你的里程可能会有所不同。

其他回答

如果你需要你的键是任何对象,而不仅仅是字符串,那么你可以使用我的jshashtable。

注意:

Several years ago, I had implemented the following hashtable, which has had some features that were missing to the Map class. However, that's no longer the case — now, it's possible to iterate over the entries of a Map, get an array of its keys or values or both (these operations are implemented copying to a newly allocated array, though — that's a waste of memory and its time complexity will always be as slow as O(n)), remove specific items given their key, and clear the whole map. Therefore, my hashtable implementation is only useful for compatibility purposes, in which case it'd be a saner approach to write a proper polyfill based on this.


function Hashtable() {

    this._map = new Map();
    this._indexes = new Map();
    this._keys = [];
    this._values = [];

    this.put = function(key, value) {
        var newKey = !this.containsKey(key);
        this._map.set(key, value);
        if (newKey) {
            this._indexes.set(key, this.length);
            this._keys.push(key);
            this._values.push(value);
        }
    };

    this.remove = function(key) {
        if (!this.containsKey(key))
            return;
        this._map.delete(key);
        var index = this._indexes.get(key);
        this._indexes.delete(key);
        this._keys.splice(index, 1);
        this._values.splice(index, 1);
    };

    this.indexOfKey = function(key) {
        return this._indexes.get(key);
    };

    this.indexOfValue = function(value) {
        return this._values.indexOf(value) != -1;
    };

    this.get = function(key) {
        return this._map.get(key);
    };

    this.entryAt = function(index) {

        var item = {};

        Object.defineProperty(item, "key", {
            value: this.keys[index],
            writable: false
        });

        Object.defineProperty(item, "value", {
            value: this.values[index],
            writable: false
        });

        return item;
    };

    this.clear = function() {

        var length = this.length;

        for (var i = 0; i < length; i++) {
            var key = this.keys[i];
            this._map.delete(key);
            this._indexes.delete(key);
        }

        this._keys.splice(0, length);
    };

    this.containsKey = function(key) {
        return this._map.has(key);
    };

    this.containsValue = function(value) {
        return this._values.indexOf(value) != -1;
    };

    this.forEach = function(iterator) {
        for (var i = 0; i < this.length; i++)
            iterator(this.keys[i], this.values[i], i);
    };

    Object.defineProperty(this, "length", {
        get: function() {
            return this._keys.length;
        }
    });

    Object.defineProperty(this, "keys", {
        get: function() {
            return this._keys;
        }
    });

    Object.defineProperty(this, "values", {
        get: function() {
            return this._values;
        }
    });

    Object.defineProperty(this, "entries", {
        get: function() {
            var entries = new Array(this.length);
            for (var i = 0; i < entries.length; i++)
                entries[i] = this.entryAt(i);
            return entries;
        }
    });
}

Hashtable类的文档

方法:

(关键) 返回与指定键相关联的值。 参数: key:从中检索值的键。


put(关键字,值) 将指定的值关联到指定的键。 参数: key:与值相关联的键。 value:与键相关联的值。


remove(键) 删除指定的键以及与之关联的值。 参数: key:要移除的键。


clear () 清除整个哈希表,通过删除其所有条目。


indexOfKey(关键) 返回指定键的索引,根据已添加的订单项。 参数: key:获取索引的键。


indexOfValue(值) 返回指定值的索引,根据已添加的订单项。 参数: value:要获取索引的值。 备注: 价值是根据身份进行比较的。


entryAt(索引) 返回一个具有键和值属性的对象,表示指定索引处的条目。 参数: index:要获取的条目的索引。


containsKey(关键) 返回哈希表是否包含指定的键。 参数: 钥匙:要找的钥匙。


containsValue(值) 返回哈希表是否包含指定的值。 参数: value:要查找的值。


forEach(迭代器) 遍历哈希表中的所有条目,调用指定的迭代器。 参数: iterator:具有三个参数:key、value和index的方法,其中index根据条目被添加的顺序表示条目的索引。

属性:

长度(只读) 获取哈希表中条目的计数。 键(只读) 获取哈希表中所有键的数组。 值(只读) 获取哈希表中所有值的数组。 条目(只读) 获取哈希表中所有项的数组。它们的表示方式与entryAt()方法相同。

var associativeArray = {};
associativeArray["one"] = "First";
associativeArray["two"] = "Second";
associativeArray["three"] = "Third";

如果你来自面向对象的语言,你应该看看这篇文章。

使用JavaScript对象作为关联数组。

关联数组:简单地说,关联数组使用字符串而不是整数作为索引。

使用

var dictionary = {};

JavaScript允许您使用以下语法向对象添加属性:

Object.yourProperty = value;

相同的另一种语法是:

Object["yourProperty"] = value;

如果可以,也可以使用以下语法创建键到值的对象映射:

var point = { x:3, y:2 };

point["x"] // returns 3
point.y // returns 2

可以使用for..in循环构造遍历关联数组,如下所示

for(var key in Object.keys(dict)){
  var value = dict[key];
  /* use key/value for intended purpose */
}

所有现代浏览器都支持JavaScript Map对象。有几个原因使得使用Map比使用Object更好:

Object有一个原型,所以映射中有默认键。 对象的键是字符串,它们可以是Map的任何值。 当你必须跟踪对象的大小时,你可以很容易地获得Map的大小。

例子:

var myMap = new Map();

var keyObj = {},
    keyFunc = function () {},
    keyString = "a string";

myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");

myMap.size; // 3

myMap.get(keyString);    // "value associated with 'a string'"
myMap.get(keyObj);       // "value associated with keyObj"
myMap.get(keyFunc);      // "value associated with keyFunc"

如果希望垃圾收集没有从其他对象引用的键,可以考虑使用WeakMap而不是Map。