javascript关联数组的键需要是字符串,还是可以是任何对象?

时间:2023-01-13 12:48:17

Do the keys of javascript associative arrays need to be strings, or can they be any object?

javascript关联数组的键需要是字符串,还是可以是任何对象?

4 个解决方案

#1


16  

There are no native associative arrays in JavaScript, only objects. 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.

JavaScript中没有本地关联数组,只有对象。对象有属性。属性的名称总是字符串:甚至数组的数值索引也会在“数组魔术”发生之前转换成字符串。

If you're looking for associative arrays with arbitrary keys, look here.

如果您正在寻找与任意键相关联的数组,请查看这里。

#2


2  

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. There is no requirements on objects used as keys or values.

键和值可以是任意的javascript对象。对于用作键或值的对象没有要求。

The mechanism is trivial. For every key there is generated unique id (per HashMap instance). That id is injected to the key object under high unlikely to collide field name ;)

机制是微不足道的。对于每个键,都会生成唯一的id(每个HashMap实例)。该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 Daniel Kwiecinski <daniel.kwiecinski@lambder.com>
 @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, Daniel Kwiecinski

祝你有个好胃口,丹尼尔Kwiecinski

#3


1  

Are you talking about Javascript objects (JSON)?

您是在说Javascript对象(JSON)吗?

The specification says that the keys should be strings http://json.org/ .

规范说键应该是string http://json.org/。

But the Javascript interpreter allows both {"key": "val"} and {key: "val"}

但是Javascript解释器同时允许{"key": "val"}和{key: "val"}

#4


0  

Building on Lambder's idea, I've implemented a small DataStructures library.

基于Lambder的想法,我实现了一个小型数据结构库。

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;

#1


16  

There are no native associative arrays in JavaScript, only objects. 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.

JavaScript中没有本地关联数组,只有对象。对象有属性。属性的名称总是字符串:甚至数组的数值索引也会在“数组魔术”发生之前转换成字符串。

If you're looking for associative arrays with arbitrary keys, look here.

如果您正在寻找与任意键相关联的数组,请查看这里。

#2


2  

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. There is no requirements on objects used as keys or values.

键和值可以是任意的javascript对象。对于用作键或值的对象没有要求。

The mechanism is trivial. For every key there is generated unique id (per HashMap instance). That id is injected to the key object under high unlikely to collide field name ;)

机制是微不足道的。对于每个键,都会生成唯一的id(每个HashMap实例)。该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 Daniel Kwiecinski <daniel.kwiecinski@lambder.com>
 @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, Daniel Kwiecinski

祝你有个好胃口,丹尼尔Kwiecinski

#3


1  

Are you talking about Javascript objects (JSON)?

您是在说Javascript对象(JSON)吗?

The specification says that the keys should be strings http://json.org/ .

规范说键应该是string http://json.org/。

But the Javascript interpreter allows both {"key": "val"} and {key: "val"}

但是Javascript解释器同时允许{"key": "val"}和{key: "val"}

#4


0  

Building on Lambder's idea, I've implemented a small DataStructures library.

基于Lambder的想法,我实现了一个小型数据结构库。

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;