Подтвердить что ты не робот

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

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

4b9b3361

Ответ 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;