简体   繁体   English

JavaScript 关联数组的键必须是字符串,还是可以是任何对象?

[英]Do the keys of JavaScript associative arrays need to be strings, or can they be any object?

JavaScript 关联数组的键必须是字符串,还是可以是任何对象?

There are no native associative arrays in JavaScript, only objects. JavaScript 中没有原生关联数组,只有对象。 Objects have properties.对象具有属性。 The names of properties are always strings: even the numeric indices of arrays will be converted to strings before the 'array magic' happens.属性的名称始终是字符串:即使是数组的数字索引也会在“数组魔术”发生之前转换为字符串

If you're looking for associative arrays with arbitrary keys, look here .如果您正在寻找具有任意键的关联数组,请查看此处

I've implemented JavaScript HashMap which code can be obtained from http://github.com/lambder/HashMapJS/tree/master我已经实现了 JavaScript HashMap,它的代码可以从http://github.com/lambder/HashMapJS/tree/master获得

The keys and values can be arbitrary JavaScript objects.键和值可以是任意的 JavaScript 对象。 There aren't any requirements on objects used as keys or values.对用作键或值的对象没有任何要求。

The mechanism is trivial.该机制是微不足道的。 For every key there is generated a unique id (per HashMap instance).对于每个键,都会生成一个唯一的 id(每个 HashMap 实例)。 That id is injected to the key object under a high unlikely to collide field name ;)该 id 被注入到不太可能发生冲突的字段名称下的关键对象;)

That id is then used to keying in the underlying baking standard JavaScript association object.然后使用该 id 键入底层烘焙标准 JavaScript 关联对象。

Here is the code:这是代码:

/*
 =====================================================================
 @license MIT
 @author Lambder
 @copyright 2009 Lambder.
 @end
 =====================================================================
 */
var HashMap = function() {
  this.initialize();
}

HashMap.prototype = {
  hashkey_prefix: "<#HashMapHashkeyPerfix>",
  hashcode_field: "<#HashMapHashkeyPerfix>",

  initialize: function() {
    this.backing_hash = {};
    this.code = 0;
  },

  /*
   Maps value to key, returning the previous association
   */
  put: function(key, value) {
    var prev;
    if (key && value) {
      var hashCode = key[this.hashcode_field];
      if (hashCode) {
        prev = this.backing_hash[hashCode];
      } else {
        this.code += 1;
        hashCode = this.hashkey_prefix + this.code;
        key[this.hashcode_field] = hashCode;
      }
      this.backing_hash[hashCode] = value;
    }
    return prev;
  },

  /*
   Returns value associated with given key
   */
  get: function(key) {
    var value;
    if (key) {
      var hashCode = key[this.hashcode_field];
      if (hashCode) {
        value = this.backing_hash[hashCode];
      }
    }
    return value;
  },
  /*
   Deletes association by given key.
   Returns true if the association existed, false otherwise
   */
  del: function(key) {
    var success = false;
    if (key) {
      var hashCode = key[this.hashcode_field];
      if (hashCode) {
        var prev = this.backing_hash[hashCode];
        this.backing_hash[hashCode] = undefined;
        if(prev !== undefined)
          success = true;
      }
    }
    return success;
  }
}

//// Usage

// Creation

var my_map = new HashMap();

// Insertion

var a_key = {};
var a_value = {struct: "structA"};
var b_key = {};
var b_value = {struct: "structB"};
var c_key = {};
var c_value = {struct: "structC"};

my_map.put(a_key, a_value);
my_map.put(b_key, b_value);
var prev_b = my_map.put(b_key, c_value);

// Retrieval

if(my_map.get(a_key) !== a_value){
  throw("fail1")
}
if(my_map.get(b_key) !== c_value){
  throw("fail2")
}
if(prev_b !== b_value){
  throw("fail3")
}

// Deletion

var a_existed = my_map.del(a_key);
var c_existed = my_map.del(c_key);
var a2_existed = my_map.del(a_key);

if(a_existed !== true){
  throw("fail4")
}
if(c_existed !== false){
  throw("fail5")
}
if(a2_existed !== false){
  throw("fail6")
}

Are you talking about JavaScript objects (JSON)?您是在谈论 JavaScript 对象 (JSON) 吗?

The specification says that the keys should be strings.规范说键应该是字符串。

But the JavaScript interpreter allows both {"key": "val"} and {key: "val"} .但是 JavaScript 解释器允许{"key": "val"}{key: "val"}

Building on Lambder's idea , I've implemented a small DataStructures library.基于Lambder 的想法,我实现了一个小型DataStructures库。

I've tested it a little and everything seems to work.我已经对其进行了一些测试,似乎一切正常。

It also automatically assigns a unique id to each HashTable/HashSet used to uniquely identify the object's key property.它还自动为每个 HashTable/HashSet 分配一个唯一的 id,用于唯一标识对象的键属性。

var DataStructure = {};

DataStructure.init = function(){
    DataStructure.initHashables();
    delete DataStructure.initHashables;
}

DataStructure.initHashables = function(){
    var objectHashableIndexer = new DataStructure.Indexer();

    DataStructure.Hashable = function(){
        var self = this;

        // Constant
        //
        //
        const ERROR_KEY_DOES_NOT_EXIST = "Key doesn't exists in Hashable when trying to pop. Associated Key Object and Hashable logged to console.";
        const HASH_MAP_KEY_PROPERTY_BASE = "DATA_STRUCTURE_HASH_MAP_KEY_PROPERTY_";

        // Attributes
        //
        //
        var tableNumber = objectHashableIndexer.getIndex();
        var tableKeyProperty = HASH_MAP_KEY_PROPERTY_BASE + tableNumber.toString();
        self.tableKeyProperty = tableKeyProperty;
        var indexer = new DataStructure.Indexer();
        var data = {};
        self.data = data;

        // Methods
        //
        //
        self.getObjectKey = function(){
            return indexer.getIndex().toString();
        }

        self.putBackObjectKey = function(index){
            indexer.putBackIndex(parseInt(index));
        }

        var getObjectKey = self.getObjectKey;
        var putBackObjectKey = self.putBackObjectKey;

        self.exists = function(key){
            if (!(tableKeyProperty in key))
                return false;

            var realKey = key[tableKeyProperty];

            if (!(realKey in data))
                return false;

            return true;
        }

        self.pop = function(key){
            if (!self.exists(key)){
                console.log(key);
                console.log(self);
                throw ERROR_KEY_DOES_NOT_EXIST;
            }
            else{
                var realKey = key[tableKeyProperty];
                delete key[tableKeyProperty];
                delete data[realKey];
                putBackObjectKey(realKey);
            }
        }

        self.destroy = function(){
            objectHashableIndexer.putBackIndex(tableNumber);
            delete self;
        }

    }

    /*
        Class DataStructure.ObjectHashMap
            Purpose: Provides a way to hash arbitrary objects to values.

            Prototype Arguments:

            Attributes:

            Methods:

            Notes:
                Should call inherited method destroy() when done with table to preserve indexes
    */
    DataStructure.ObjectHashMap = function(){
        DataStructure.Hashable.call(this);
        var self = this;

        // Constant
        //
        //
        const ERROR_KEY_EXISTS = "Key already exists in ObjectHashMap when trying to push. Associated Key Object and ObjectHashMap logged to console.";
        const ERROR_KEY_DOES_NOT_EXIST = "Key doesn't exists in ObjectHashMap when trying to getValue. Associated Key Object and ObjectHashMap logged to console.";

        // Attributes
        //
        //

        var tableKeyProperty;
        var data;

        // Initialization
        //
        //
        self.init = function(){
            self.privatize();
            delete self.privatize;
        }

        self.privatize = function(){
            tableKeyProperty = self.tableKeyProperty;
            delete self.tableKeyProperty;

            getObjectKey = self.getObjectKey;
            delete self.getObjectKey;

            putBackObjectKey = self.putBackObjectKey;
            delete self.putBackObjectKey;

            data = self.data;
            delete self.data;
        }

        // Methods
        //
        //
        var getObjectKey;
        var putBackObjectKey;

        self.push = function(key, value){
            if (self.exists(key)){
                console.log(key);
                console.log(self);
                throw ERROR_KEY_EXISTS;
            }
            else{
                var realKey = getObjectKey();
                key[tableKeyProperty] = realKey;
                data[realKey] = value;
            }
        }

        self.getValue = function(key){
            if(!self.exists(key)){
                console.log(key);
                console.log(self);
                throw ERROR_KEY_DOES_NOT_EXIST;
            }
            else{
                var realKey = key[tableKeyProperty];
                return data[realKey];
            }
        }

        self.init();
        delete self.init;
    }

    /*
        Class DataStructure.ObjectHashSet
            Purpose: Provides a way to store arbitrary objects and check that they exist.

            Prototype Arguments:

            Attributes:

            Methods:

            Notes:
                Should call inherited method destroy() when done with table to preserve indexes
    */
    DataStructure.ObjectHashSet = function(){
        DataStructure.Hashable.call(this);
        var self = this;

        // Constant
        //
        //
        const ERROR_KEY_EXISTS = "Key already exists in ObjectHashSet when trying to push. Associated Key Object and ObjectHashSet logged to console.";
        const ERROR_KEY_DOES_NOT_EXIST = "Key doesn't exists in ObjectHashSet when trying to getValue. Associated Key Object and ObjectHashSet logged to console.";

        // Attributes
        //
        //

        var tableKeyProperty;
        var data;

        // Initialization
        //
        //
        self.init = function(){
            self.privatize();
            delete self.privatize;
        }

        self.privatize = function(){
            tableKeyProperty = self.tableKeyProperty;
            delete self.tableKeyProperty;

            getObjectKey = self.getObjectKey;
            delete self.getObjectKey;

            putBackObjectKey = self.putBackObjectKey;
            delete self.putBackObjectKey;

            data = self.data;
            delete self.data;
        }

        // Methods
        //
        //
        var getObjectKey;
        var putBackObjectKey;

        self.push = function(key){
            if (self.exists(key)){
                console.log(key);
                console.log(self);
                throw ERROR_KEY_EXISTS;
            }
            else{
                var realKey = getObjectKey();
                key[tableKeyProperty] = realKey;
                data[realKey] = "";
            }
        }

        self.init();
        delete self.init;
    }

}


DataStructure.Indexer = function(){
    var self = this;

    // Constant
    //
    //
    const DEFAULT_SIZE = 1000;

    // Attributes
    //
    //
    var nextIndex = 0;
    var availableIndicies = 0;
    var freeIndicies = [];

    // Initialization
    //
    //
    self.init = function(){
        freeIndicies.length = DEFAULT_SIZE;
    }

    // Methods
    //
    //
    self.getIndex = function(){
        var index = 0;

        if (availableIndicies === 0){
            index = nextIndex;
            ++nextIndex;
        }
        else{
            --availableIndicies;
            index = freeIndicies[availableIndicies];
        }

        return index;
    }

    self.putBackIndex = function(index){
        if (availableIndicies === freeIndicies.length)
            freeIndicies.push(index);
        else
            freeIndicies[availableIndicies] = index;

        ++availableIndicies;
    }

    self.init();
    delete self.init;
}

DataStructure.init();
delete DataStructure.init;

It depends on what you mean by "associative arrays".这取决于您所说的“关联数组”是什么意思。 There is nothing called "associative arrays" in JavaScript, there are objects and there are maps. JavaScript 中没有所谓的“关联数组”,有对象也有映射。

Objects are the ones that can be accessed using the [] notation, for example foo["bar"] , and there the keys have to be strings, as Christoph's answer explains.对象是可以使用[]符号访问的对象,例如foo["bar"] ,并且键必须是字符串,正如Christoph 的回答所解释的那样。

There are also maps , which can have any object as keys.还有maps ,它可以将任何对象作为键。 However, to access them, you can't use [] as for objects, you must use the get and set methods.但是,要访问它们,不能像对象一样使用[] ,必须使用getset方法。 Here is an example how to use them:以下是如何使用它们的示例:

let myMap = new Map();    // Create the map
myMap.set("key", "value");    // To set a value, use the set method.
                            // The first argument is the key, the second one is the value.
myMap.set(Math, "bar");    // You can really use any object as key
myMap.set(console.log, "hello");    // Including functions
myMap.set(document.body, "world");    // And even DOM elements

// To get the value associated to a key, use the get method
console.log(myMap.get(Math));    // "bar"
console.log(myMap.get(document.body));    // "world"

In this example I used built-in objects as keys in order to avoid cluttering the example with defining new objects to use as keys, but it's of course possible to use your own objects as keys.在本示例中,我使用内置对象作为键,以避免将示例定义为用作键的新对象而使示例混乱,但当然也可以使用您自己的对象作为键。

Be careful, however, not to use [] to access elements of a map.但是,请注意不要使用[]来访问地图的元素。 Doing myMap[whatever] is valid code so it won't throw an error, but it won't work as expected:执行myMap[whatever]是有效代码,因此不会引发错误,但不会按预期工作:

// Don't do this
myMap[Math] = 3;
myMap["[object Math]"] = 4;
console.log(myMap[Math]);    //4
console.log(myMap.get(Math));    // 'undefined'

// Do this instead
myMap.set(Math, 3);
myMap.set("[object Math]", 4);
console.log(myMap.get(Math));    //3

To learn more about maps, see Map .要了解有关地图的更多信息,请参阅地图

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用JavaScript在关联数组中查找键 - Finding Keys in associative arrays with JavaScript 带有Java字符串数组中的键的关联数组 - Associative Array with keys from an Array of Strings in Javascript 按字母顺序对关联数组/ javascript对象进行排序 - Sorting associative array / javascript object by keys alphabetically javascript对象过滤器-不返回关联键 - javascript object filter - not returning associative keys 关联数组如何在JavaScript中工作? - How do associative arrays work in JavaScript? 需要检查 object javascript 中是否有两个密钥中的任何一个 - Need to check if any one of two keys are there in object javascript 将对象作为键(不是字符串而是唯一对象)的关联映射的javascript方法是什么? - What is the javascript approach to an associative map with objects as keys (not strings but unique objects)? 如何从一个对象创建一个字符串数组,其中各个键的值是单独的字符串数组? - How do I create an array of strings from an object where the values of individual keys are separate arrays of strings? 使用字符串作为键迭代JavaScript对象 - Iterating JavaScript object with strings as keys 将Javascript对象键转换为字符串 - Convert Javascript Object keys to strings
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM