Должны ли ключи ассоциативных массивов 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;