Creating a .net like dictionary object in Javascript - javascript

I want to create a object in JavaScript which will store values in key, value pair and I should be able to pass some key and should be able to get its value back. In .NET world we can use dictionary class for this kind of implementation. Do we have any option in JavaScript world? I am using ExtJs 4.1, so if you know of any option in ExtJS even that would work.
I have tried something like this but I cannot get value by key.
var Widget = function(k, v) {
this.key = k;
this.value = v;
};
var widgets = [
new Widget(35, 312),
new Widget(52, 32)
];

Just use a standard javascript object:
var dictionary = {};//create new object
dictionary["key1"] = value1;//set key1
var key1 = dictionary["key1"];//get key1
NOTE: You can also get/set any "keys" you create using dot notation (i.e. dictionary.key1)
You could take that further if you wanted specific functions for it...
function Dictionary(){
var dictionary = {};
this.setData = function(key, val) { dictionary[key] = val; }
this.getData = function(key) { return dictionary[key]; }
}
var dictionary = new Dictionary();
dictionary.setData("key1", "value1");
var key1 = dictionary.getData("key1");

How about this class taken from Marijn Havereke's book Eloquent JavaScript
The fiddle
function Dictionary(values) {
this.values = values || {};
var forEachIn = function (object, action) {
for (var property in object) {
if (Object.prototype.hasOwnProperty.call(object, property))
action(property, object[property]);
}
};
Dictionary.prototype.containsKey = function(key) {
return Object.prototype.hasOwnProperty.call(this.values, key) &&
Object.prototype.propertyIsEnumerable.call(this.values, key);
};
Dictionary.prototype.forEach = function(action) {
forEachIn(this.values, action);
};
Dictionary.prototype.lookup = function(key) {
return this.values[key];
};
Dictionary.prototype.add = function(key, value) {
this.values[key] = value;
};
};
var numberDic = new Dictionary({One: 1,Two: 2, Three: 3});
//-- does key exist
console.log(numberDic.containsKey("One"));
console.log(numberDic.containsKey("One"));
console.log(numberDic.containsKey("Four"));
//-- loop through each item in the dic
numberDic.forEach(function(key, value) {
console.log(key, "is", value);
});
//-- works with complex objects
//------------------------------------------
var complexObjectDic = new Dictionary({
Microsoft: {
Something: "Real Interesting",
About: "Microsoft",
Will: "Go",
Here: ".",
ProductPrices: {
WindowsPhone: 55.88,
Windows :{
WinXp : 180.00,
Win7 : 200.00,
Win8 : 150.00
}
}
},
Apple: {
Did: "you",
Hear: "the",
New: "iphone",
Will: "be coming out soon",
}});
//-- does key exist
console.log(complexObjectDic.containsKey("Microsoft"));
console.log(complexObjectDic.containsKey("Apple"));
console.log(complexObjectDic.containsKey("Facebook"));
//-- search the dic by key
console.log(complexObjectDic.lookup("Microsoft"));
console.log(complexObjectDic.lookup("Apple"));
//-- add item to dic
complexObjectDic.add("Instagram", {
This: "is",
Another: "object",
That: "I willl be Adding"
});
//-- loop through each item in the dic
complexObjectDic.forEach(function(key, value) {
console.log(key, value);
});

var widget={};
var key='k';
widget[key]='v';
alert(widget.k);//gives you v

Related

Run a function when deep property is set

I have an object like
const obj = { field1: obj1, field2: obj2 }
and now I'd like to run a function when anything in obj was changed:
function objChanged() { ... }
// decorate obj somehow ...
obj.field3 = data; // objChanged should be called (Proxy can see it)
obj.field1.val = data; //objChanged should be called (Proxy can't see it?)
AFAIK there is a MutationObserver which works only for DOM and Proxy which intercepts only own properties, right?
I do not own obj1 so I can not change it. Is there a way to achieve this functionality?
Following the piece of code will listen to object property you can iterate over object properties to listen all. I am curious, what are you trying to achieve?
const dog = { bark: true };
function Observer(o, property) {
var _this = this;
this.observers = [];
this.Observe = function (notifyCallback) {
_this.observers.push(notifyCallback);
};
Object.defineProperty(o, property, {
set: function (val) {
_this.value = val;
for (var i = 0; i < _this.observers.length; i++) {
_this.observers[i](val);
}
},
get: function () {
return _this.value;
},
});
}
const observer = new Observer(dog, "bark");
observer.Observe(function (value) {
l("Barked");
});
dog.bark = true;
dog.bark = true;
dog.bark = true;
dog.bark = true;
Orgil's answer works only with a single property that needs to be known and encoded. I wanted a solution which works for all properties, including later added. Inspired by his idea to create an observing object, I created a dynamic Proxy that adds another Proxies when needed.
In the following code dog1 serves as proxy: setting its properties modifies the original dog object and logs the assigned value to console.
function AssignProxy(o, fn, path) {
var tree = {};
if(!path) path = "obj";
return new Proxy(o, {
get: (_, prop) => {
if(typeof o[prop] != "object") return o[prop];
if(tree[prop] === undefined) tree[prop] = AssignProxy(o[prop], fn, `${path}.${prop}`);
return tree[prop];
},
set: (_, prop, val) => fn(o[prop] = val, prop, o, path) || 1
});
}
/****** TEST *******/
const dog = {
sounds: {},
name: "Spike"
};
let callback = (val, prop, o, path) => console.log(`assigning ${path}.${prop} to ${val}`)
const dog1 = AssignProxy(dog, callback, "dog1");
dog1.name = "Tyke"; // overwrite property
dog1.age = 4; // create a property
dog1.sounds.howl = "hoooooowl"; // create a deep property
dog1.sounds.howl = {text: "hoowl", pitch: 5000}; // overwrite the deep property
var howl = dog1.sounds.howl; // access by reference
howl.pitch = 6000; // overwrite later added property
console.log(dog); // verify the original object

Access dynamically created objects in Javascript

I am attempting to dynamically create an object with name-value pairs using html input fields. This is what i have so far:
var taskComplete = {
newTask: function(arg) {
var fieldObj = {},
selector = arg,
inputFields = document.getElementsByClassName(selector);
for (var i=0;i<inputFields.length;i++) {
var attrValue = inputFields[i].getAttribute("name"),
value = inputFields[i].value,
newFieldObj = fieldObj[i] = {[attrValue]: value };
console.log(newFieldObj);
}
}
}
taskComplete.newTask('input');
The console log outputs:
Object {title: ""}
Object {description: ""}
Object {date: ""}
Question1:
How do i access these objects? they all share the same name eg. 'Object' so 'object.title' does not work.
Question2:
Is there a way to combine these objects into a single object?
eg.
var obj = {
title: "",
description: "",
date: "",
}
code example with html: codepen.io
Hope this make sense. Thank you for any and all assistance.
I will answer your questions in the reverse order, makes more sense, you will see.
Question2: Is there a way to combine these objects into a single object?
Yes, I am happy to inform you that you absolutely can. Where you do
newFieldObj = fieldObj[i] = {[attrValue]: value };
simply do
fieldObj[attrValue] = value;
What this does, is the following: On the fieldObj, which is a plain {} set a key named after the value of attrValue and pair that key with the value value
Question1: How do i access these objects? they all share the same name eg. 'Object' so 'object.title' does not work.
In order to be able to access these objects, your newTask method should be returning them. So, at the end of your newTask method, simply do return fieldObj; like so
var taskComplete = {
newTask: function(arg) {
var fieldObj = {},
selector = arg,
inputFields = document.getElementsByClassName(selector),
attrValue,
value;
for (var i=0;i<inputFields.length;i++) {
attrValue = inputFields[i].getAttribute("name");
value = inputFields[i].value;
fieldObj[attrValue] = value;
}
return fieldObj;
}
}
and then store the returned value to a new variable like so:
var aFancyName = taskComplete.newTask('input');
Here's the modified pen: http://codepen.io/anon/pen/XdjKQJ
Not super clear on what you are trying to do here.
Instead of creating a new object for each iteration of your loop, why not just assign those properties to the fieldObj you already have?
Then you can just return that object and do whatever you want with it in the calling code:
'use strict';
// ** TASK OBJECT ** //
var taskComplete = {
newTask: function(selector) {
var fieldObj = {},
inputFields = document.getElementsByClassName(selector);
for (var i = 0; i < inputFields.length; i++) {
var attrKey = inputFields[i].getAttribute("name"),
value = inputFields[i].value;
fieldObj[attrKey] = value;
}
return fieldObj;
}
}
var o = taskComplete.newTask('input');
console.dir(o);
http://codepen.io/anon/pen/reMLPB?editors=0010

how to get the content of java script object in another object?

how to get the content of java script object in another object ?
let say my variable are like follows :
var credentials ={
"name":userName,
"passwd":password
}
var params={
"Credentials":credentials
}
am passing params as an parameter to same other function.In that function i have another object pkt ,as follows :
var pkt={
"name":xxx,
//XXXX
}
what to code at XXXX so that my final pkt structure should be like:
pkt={
"name":xxx,
"Credentials": {
"name":userName,
"passwd":password
}
}
we may have multiple objects inside params,the requirement is that the key value pair should come accordingly.
the equivalent java code is as follows:
Iterator iterKeys = params.keySet().iterator();
while (iterKeys.hasNext())
{
String key = (String)iterKeys.next();
JSONValue value = params.get(key);
pkt.put(key, value);
}
Thanks.
Javascript objects are just Hashmaps.
var credentials = {
"name": "userName",
"passwd": "password"
}
var params = {
"Credentials": credentials
}
var pkt = {
"name": "xxx",
}
for (var property in params) {
if (params.hasOwnProperty(property)) {
var value = property;
pkt[property] = params[property];
}
}
alert(JSON.stringify(pkt));
You can just assign as seen in [this fiddle]
(http://jsfiddle.net/TfWMy/)
You could use a library function like $.extend or _.extend:
pkt = $.extend(pkt, params);
Otherwise you can loop through params and add each key/value pair to pkt:
for (var key in params){
pkt[key] = params[key];
}
Use hasOwnProperty to avoid looping over ancestor members.
You can also use associative array structure.
i.e
var credentials = {
"name": "userName",
"passwd": "password"
}
var pkt = {
"name": "xxx",
}
pkt["Credentials"] = credentials
Not particularly sure about this, but this should work as expected.
Here's two quick functions that should do what you're looking for. The first adds the keys and values to a new object, the second function adds the keys and values to the first object.
var mergeObjectsToNew = function(o1, o2) {
var r = {};
for (var key in o1) {
r[key] = o1[key];
}
for (var key in o2) {
r[key] = o2[key];
}
return r;
}
var mergeObjects = function(o1, o2) {
for (var key in o2) {
o1[key] = o2[key];
}
return o1;
}
I think you are looking to extend your object with another.
Please follow the code and I hope this is the thing you are require.
var credentials ={
"name":"",
"passwd":""
}
var params={
"Credentials":credentials
}
var pkt={
name:"ABC"
};
function Extends(param1,param2){
var object = $.extend({}, param1, param2);
console.log(object);
}
Extends(params,pkt);
Please find Fiddle Below
Fiddle

Stringify (convert to JSON) a JavaScript object with circular reference

I've got a JavaScript object definition which contains a circular reference: it has a property that references the parent object.
It also has functions that I don't want to be passed through to the server. How would I serialize and deserialize these objects?
I've read that the best method to do this is to use Douglas Crockford's stringify. However, I'm getting the following error in Chrome:
TypeError: Converting circular structure to JSON
The code:
function finger(xid, xparent){
this.id = xid;
this.xparent;
//other attributes
}
function arm(xid, xparent){
this.id = xid;
this.parent = xparent;
this.fingers = [];
//other attributes
this.moveArm = function() {
//moveArm function details - not included in this testcase
alert("moveArm Executed");
}
}
function person(xid, xparent, xname){
this.id = xid;
this.parent = xparent;
this.name = xname
this.arms = []
this.createArms = function () {
this.arms[this.arms.length] = new arm(this.id, this);
}
}
function group(xid, xparent){
this.id = xid;
this.parent = xparent;
this.people = [];
that = this;
this.createPerson = function () {
this.people[this.people.length] = new person(this.people.length, this, "someName");
//other commands
}
this.saveGroup = function () {
alert(JSON.stringify(that.people));
}
}
This is a test case that I created for this question. There are errors within this code but essentially I have objects within objects, and a reference passed to each object to show what the parent object is when the object is created. Each object also contains functions, which I don't want stringified. I just want the properties such as the Person.Name.
How do I serialize before sending to the server and deserialize it assuming that the same JSON is passed back?
Circular structure error occurs when you have a property of the object which is the object itself directly (a -> a) or indirectly (a -> b -> a).
To avoid the error message, tell JSON.stringify what to do when it encounters a circular reference.
For example, if you have a person pointing to another person ("parent"), which may (or may not) point to the original person, do the following:
JSON.stringify( that.person, function( key, value) {
if( key == 'parent') { return value.id;}
else {return value;}
})
The second parameter to stringify is a filter function. Here it simply converts the referred object to its ID, but you are free to do whatever you like to break the circular reference.
You can test the above code with the following:
function Person( params) {
this.id = params['id'];
this.name = params['name'];
this.father = null;
this.fingers = [];
// etc.
}
var me = new Person({ id: 1, name: 'Luke'});
var him = new Person( { id:2, name: 'Darth Vader'});
me.father = him;
JSON.stringify(me); // so far so good
him.father = me; // time travel assumed :-)
JSON.stringify(me); // "TypeError: Converting circular structure to JSON"
// But this should do the job:
JSON.stringify(me, function( key, value) {
if(key == 'father') {
return value.id;
} else {
return value;
};
});
BTW, I'd choose a different attribute name to "parent" since it is a reserved word in many languages (and in DOM). This tends to cause confusion down the road...
No-lib
Use below replacer to generate json with string references (similar to json-path) to duplicate/circular referenced objects
let s = JSON.stringify(obj, refReplacer());
function refReplacer() {
let m = new Map(), v= new Map(), init = null;
return function(field, value) {
let p= m.get(this) + (Array.isArray(this) ? `[${field}]` : '.' + field);
let isComplex= value===Object(value)
if (isComplex) m.set(value, p);
let pp = v.get(value)||'';
let path = p.replace(/undefined\.\.?/,'');
let val = pp ? `#REF:${pp[0]=='[' ? '$':'$.'}${pp}` : value;
!init ? (init=value) : (val===init ? val="#REF:$" : 0);
if(!pp && isComplex) v.set(value, path);
return val;
}
}
// ---------------
// TEST
// ---------------
// gen obj with duplicate references
let a = { a1: 1, a2: 2 };
let b = { b1: 3, b2: "4" };
let obj = { o1: { o2: a }, b, a }; // duplicate reference
a.a3 = [1,2,b]; // circular reference
b.b3 = a; // circular reference
let s = JSON.stringify(obj, refReplacer(), 4);
console.log(s);
And following parser function to regenerate object from such "ref-json"
function parseRefJSON(json) {
let objToPath = new Map();
let pathToObj = new Map();
let o = JSON.parse(json);
let traverse = (parent, field) => {
let obj = parent;
let path = '#REF:$';
if (field !== undefined) {
obj = parent[field];
path = objToPath.get(parent) + (Array.isArray(parent) ? `[${field}]` : `${field?'.'+field:''}`);
}
objToPath.set(obj, path);
pathToObj.set(path, obj);
let ref = pathToObj.get(obj);
if (ref) parent[field] = ref;
for (let f in obj) if (obj === Object(obj)) traverse(obj, f);
}
traverse(o);
return o;
}
// ------------
// TEST
// ------------
let s = `{
"o1": {
"o2": {
"a1": 1,
"a2": 2,
"a3": [
1,
2,
{
"b1": 3,
"b2": "4",
"b3": "#REF:$.o1.o2"
}
]
}
},
"b": "#REF:$.o1.o2.a3[2]",
"a": "#REF:$.o1.o2"
}`;
console.log('Open Chrome console to see nested fields:');
let obj = parseRefJSON(s);
console.log(obj);
It appears that dojo can represent circular references in JSON in the form : {"id":"1","me":{"$ref":"1"}}
Here is an example:
http://jsfiddle.net/dumeG/
require(["dojox/json/ref"], function(){
var me = {
name:"Kris",
father:{name:"Bill"},
mother:{name:"Karen"}
};
me.father.wife = me.mother;
var jsonMe = dojox.json.ref.toJson(me); // serialize me
alert(jsonMe);
});​
Produces:
{
"name":"Kris",
"father":{
"name":"Bill",
"wife":{
"name":"Karen"
}
},
"mother":{
"$ref":"#father.wife"
}
}
Note: You can also de-serialize these circular referenced objects using the dojox.json.ref.fromJson method.
Other Resources:
How to serialize DOM node to JSON even if there are circular references?
JSON.stringify can't represent circular references
I found two suitable modules to handle circular references in JSON.
CircularJSON https://github.com/WebReflection/circular-json whose output can be used as input to .parse(). It also works in Browsers & Node.js Also see: http://webreflection.blogspot.com.au/2013/03/solving-cycles-recursions-and-circulars.html
Isaacs json-stringify-safe https://github.com/isaacs/json-stringify-safe which maybe more readable but can't be used for .parse and is only available for Node.js
Either of these should meet your needs.
Happened upon this thread because I needed to log complex objects to a page, since remote debugging wasn't possible in my particular situation. Found Douglas Crockford's (inceptor of JSON) own cycle.js, which annotates circular references as strings such that they can be reconnected after parsing. The de-cycled deep copy is safe to pass through JSON.stringify. Enjoy!
https://github.com/douglascrockford/JSON-js
cycle.js: This file contains two functions, JSON.decycle and
JSON.retrocycle, which make it possible to encode cyclical structures
and dags in JSON, and to then recover them. This is a capability that
is not provided by ES5. JSONPath is used to represent the links.
I used the following to eliminate the circular references:
JS.dropClasses = function(o) {
for (var p in o) {
if (o[p] instanceof jQuery || o[p] instanceof HTMLElement) {
o[p] = null;
}
else if (typeof o[p] == 'object' )
JS.dropClasses(o[p]);
}
};
JSON.stringify(JS.dropClasses(e));

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

Do the keys of JavaScript associative arrays need to be strings, or can they be any object?
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.
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
The keys and values can be arbitrary JavaScript objects.
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).
That id is injected to the key object under a high unlikely to collide field name ;)
That id is then used to keying in the underlying baking standard JavaScript association object.
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)?
The specification says that the keys should be strings.
But the JavaScript interpreter allows both {"key": "val"} and {key: "val"}.
Building on Lambder's idea, I've implemented a small DataStructures library.
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.
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.
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.
There are also maps, which can have any object as keys. However, to access them, you can't use [] as for objects, you must use the get and set methods. 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:
// 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.

Categories

Resources