Должны ли ключи ассоциативных массивов javascript быть строками или они могут быть любыми объектами?

Должны ли ключи ассоциативных массивов javascript быть строками или они могут быть любыми объектами?

Ответ 1

В JavaScript нет встроенных ассоциативных массивов, а только объектов. Объекты имеют свойства. Имена свойств всегда являются строками: даже числовые индексы массивов будут преобразованы в строки до того, как произойдет "массивная магия".

Если вы ищете ассоциативные массивы с произвольными ключами, смотрите здесь.

Ответ 2

Я реализовал javascript HashMap, код которого можно получить из http://github.com/lambder/HashMapJS/tree/master

Ключи и значения могут быть произвольными объектами javascript. Нет требований к объектам, используемым в качестве ключей или значений.

Механизм тривиален. Для каждого ключа создается уникальный идентификатор (для экземпляра HashMap). Этот идентификатор вводится ключевому объекту при очень маловероятном совпадении имени поля;)

Этот идентификатор затем используется для ввода базового объекта ассоциации javascript для стандартного выпечки.

Вот код:

/*
 =====================================================================
 @license MIT
 @author Daniel Kwiecinski <[email protected]>
 @copyright 2009 Daniel Kwiecinski.
 @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 previous assocciation
   */
  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 assocciation 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")
}

Bon Appétit, Даниэль Квецинский

Ответ 3

Вы говорите о объектах Javascript (JSON)?

В спецификации указано, что ключи должны быть строками http://json.org/.

Но интерпретатор Javascript допускает как {"key": "val"}, так и {key: "val"}

Ответ 4

Основываясь на идее Lambder, я реализовал небольшую библиотеку DataStructures.

Я тестировал это немного, и все, кажется, работает.

Он также автоматически присваивает уникальный идентификатор каждому HashTable/HashSet, используемому для уникальной идентификации свойства ключа объекта.

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;