当前位置:  开发笔记 > 编程语言 > 正文

如何在JavaScript中进行关联数组/散列

如何解决《如何在JavaScript中进行关联数组/散列》经验,为你挑选了9个好方法。

我需要使用JavaScript存储一些统计信息,就像我在C#中这样做:

Dictionary statistics;

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

JavaScript中是否有Hashtable类似的东西Dictionary
我怎么能以这种方式存储价值?



1> Alek Davis..:

将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 */
}


请注意,作者使用`new Array()`初始化"关联数组"的方法是不受欢迎的.这篇文章最终提到了它的缺点,并建议将"新的Object()"或"{}"作为首选替代品,但这已接近尾声,我担心大多数读者都不会那么做.
失败.JavaScript不支持将对象引用作为键,而像Flash/AS3 Dictionary那样.在JavaScript中,`var obj1 = {}; var obj2 = {}; var table = {}; table [obj1] ="A"; table [obj2] ="B"; 警报(表[OBJ1]); //显示B`,因为它无法区分键obj1和obj2; 它们都被转换为字符串,就像"对象"一样.完全失败,并使用引用和循环引用进行类型安全的序列化,在JavaScript中完整无效或不具有性能.在Flash/AS3中很容易.
@Leo该示例似乎是错误的。字典的`for ... in`会在其键上循环,因此'Object.keys'似乎放错了地方。“ Object.keys”返回字典键的数组,而“ for ... in”则表示该数组在*其*“ keys”上循环,而“ keys”是数组的索引,而不是其值。

2> Dani Cricco..:
var associativeArray = {};
associativeArray["one"] = "First";
associativeArray["two"] = "Second";
associativeArray["three"] = "Third";

如果您来自面向对象语言,请查看本文.


你也可以用更少的行来做:var associativeArray = {"one":"First","two":"second","three":"Third"}; 然后associativeArray ["one"]返回"First",assocativeArray ["four"]返回null.
抱歉@JuusoOhtonen,我6年前写了这篇文章(真是太快了,这真是令人难以置信)。我已经更新了链接。请检查它,不要犹豫,问您是否有任何疑问

3> roryf..:

除非您有特殊原因,否则只需使用普通对象即可.可以使用散列表样式语法引用Javascript中的对象属性:

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

现在可以将两者foobar元素引用为:

hashtable['foo'];
hashtable['bar'];
// or
hashtable.foo;
hashtable.bar;

当然这意味着你的密钥必须是字符串.如果它们不是字符串,则会在内部转换为字符串,因此它可能仍然有效,YMMV.


这个例子令人困惑,因为你在两个实例中使用foo和bar作为键和值.更清楚地表明`var dict = {}; dict.key1 ="val1"; dict ["key2"] ="val2";`dict的key1元素可以通过`dict ["key1"]`和`dict.key1`等效引用.
如果你的一个键是"__proto__"或"__parent__"怎么办?
Jonas:请记住,在设置属性时,整数会转换为字符串:`var hash = {}; hash [1] ="foo"; alert(hash ["1"]);`alert"foo".
请注意,***对象不能在JavaScript中用作键***.嗯,他们可以,但他们被转换为他们的字符串表示,所以任何对象将最终作为完全相同的键.请参阅下面的@ TimDown的jshashtable建议.

4> Vitalii Fedo..:

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

Object有一个原型,因此地图中有默认键.

Object的键是字符串,它们可以是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.


在写完这个答案一年多之后,"所有现代浏览器都支持Map"仍然不是真的.只有在桌面上才能依靠至少基本的地图支持.不在移动设备上.例如,Android浏览器根本没有Map支持.即使在桌面上,一些实现也是不完整的.例如,IE11仍然不支持枚举"for ... of ...",所以如果你想要IE兼容性,你必须使用恶心的.forEach kludge.此外,JSON.stringify()在我尝试过的任何浏览器中都不适用于Map.初始化程序也不能在IE或Safari中使用.
希望在几年内,这将是最受欢迎的答案.

5> Shog9..:

由于JS中的每个对象都表现得像 - 并且通常被实现为 - 一个哈希表,我只是去...

var hashSweetHashTable = {};


Downvoted,因为它没有显示如何实际访问"哈希表"中的值.

6> Raj..:

所以在C#代码看起来像:

Dictionary dictionary = new Dictionary();
dictionary.add("sample1", 1);
dictionary.add("sample2", 2);

要么

var dictionary = new Dictionary {
    {"sample1", 1},
    {"sample2", 2}
};

在JavaScript中

var dictionary = {
    "sample1": 1,
    "sample2": 2
}

C#dictionary对象包含有用的方法,比如dictionary.ContainsKey() 在JavaScript中我们可以使用hasOwnProperty类似的方法

if (dictionary.hasOwnProperty("sample1"))
    console.log("sample1 key found and its value is"+ dictionary["sample1"]);



7> Tim Down..:

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


在我找到这个之前,我花了几个小时磕磕绊绊地认为对象不能真正用作JS-style-Object-as-associative-arrays的键?蒂姆,谢谢你.

8> Davide Canni..:

我创建它来实现一些问题,例如对象键映射,枚举能力(带forEach()方法)和清除.

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

方法:

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

put(key, value)
将指定的值与指定的键关联.
参数::
key关联值的键.
value:要与键关联的值.

remove(key)
删除指定的键及其值.
参数::
key要删除的键.

clear()
清除所有哈希表,删除键和值.

indexOfKey(key)
根据添加顺序返回指定键的索引.
参数::
key获取索引的关键字.

indexOfValue(value)
根据添加顺序返回指定值的索引.
参数::
value获取索引的值.
注意:
此信息是通过indexOf()数组的方法检索的,因此它只是将toString()方法与对象进行比较.

entryAt(index)
返回具有两个属性的对象:key和value,表示指定索引处的条目.
参数::
index要获取的条目的索引.

containsKey(key)
返回哈希表是否包含指定的键.
参数::
key要检查的键.

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

forEach(iterator)
迭代指定的所有条目iterator.
参数:
value::用3个参数的方法key,valueindex,其中,index表示所述条目的索引.

属性:

length (只读)
获取哈希表中条目的计数.

keys (只读)
获取哈希表中所有键的数组.

values (只读)
获取哈希表中所有值的数组.

entries (只读)
获取哈希表中所有条目的数组.它们以与该方法相同的形式表示entryAt().



9> Birey..:
function HashTable() {
    this.length = 0;
    this.items = new Array();
    for (var i = 0; i < arguments.length; i += 2) {
        if (typeof (arguments[i + 1]) != 'undefined') {
            this.items[arguments[i]] = arguments[i + 1];
            this.length++;
        }
    }

    this.removeItem = function (in_key) {
        var tmp_previous;
        if (typeof (this.items[in_key]) != 'undefined') {
            this.length--;
            var tmp_previous = this.items[in_key];
            delete this.items[in_key];
        }

        return tmp_previous;
    }

    this.getItem = function (in_key) {
        return this.items[in_key];
    }

    this.setItem = function (in_key, in_value) {
        var tmp_previous;
        if (typeof (in_value) != 'undefined') {
            if (typeof (this.items[in_key]) == 'undefined') {
                this.length++;
            } else {
                tmp_previous = this.items[in_key];
            }

            this.items[in_key] = in_value;
        }

        return tmp_previous;
    }

    this.hasItem = function (in_key) {
        return typeof (this.items[in_key]) != 'undefined';
    }

    this.clear = function () {
        for (var i in this.items) {
            delete this.items[i];
        }

        this.length = 0;
    }
}


我没有投票但是......你不应该使用数组作为对象.不是100%确定这是否是你的意图.在数组上使用slice不能删除以重新索引; 删除是好的,但将设置为undefined - 更好地显示; 在一个对象上使用= undefined也是b/c它更快(但内存更多).简而言之:总是使用一个对象:`{}`不是数组:`[]`或`new Array()`如果你打算有字符串键,否则js引擎有问题 - 它会看到2种类型1个变量,这意味着没有优化,或者它将与数组一起运行并意识到它必须更改为对象(可能的重新分配).
就像亚历克斯霍金斯的回答一样,请提供一些解释为什么这个相当复杂的代码实际上是有用的,并且比这里给出的其他更短的答案更好.
推荐阅读
刘美娥94662
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有