Reputation: 2611
I have a set of key/values eg orange=123, banana=4, apple=567. How can I store these key/values in a javascript object such that I can:
It seems that for 1. an object literal would be suitable but the iteration order is not guaranteed and that for 2. an array of key/value pairs (object literals) would provide an iteration order but not the ability to lookup the value based on a key.
@* Thanks for all the answers - Is this problem not a common one? Do libraries like jQuery not include support for this kind of type?
Upvotes: 2
Views: 10295
Reputation: 122956
How about cooking your own list constructor?
function List(obj) {
if (this instanceof List) {
var t = this,
keys = [];
/* inititalize: add the properties of [obj] to the list,
and store the keys of [obj] in the private keys array */
for (var l in obj) {
keys.push(l);
t[l] = obj[l];
}
/* public:
add a property to the list
*/
t.add =
function(key, value) {
t[key] = value;
keys.push(key);
return t; /* allows method chaining */
};
/* public:
return raw or sorted list as string, separated by [separator]
Without [sort] the order of properties is the order in which
the properties are added to the list
*/
t.iterate =
function(sort,separator){
separator = separator || '\n';
var ret = [],
lkeys = sort ? keys.slice().sort() : keys;
for (var i=0;i<lkeys.length;i++){
ret.push(lkeys[i]+': '+t[lkeys[i]]);
}
return ret.join(separator);
};
} else if (obj && obj instanceof Object) {
return new List(obj);
} else if (arguments.length === 2) {
var a = {};
a[String(arguments[0])] = arguments[1];
return new List(a);
} else { return true; }
/* the 'if (this instanceof List)' pattern makes
the use of the 'new' operator obsolete. The
constructor also allows to be initialized with
2 parameters => 'List(key,value)'
*/
}
now you can have it raw (the order you added props is maintained) or sorted:
var myList =
List( { orange:123,
banana:4,
apple:567 }
);
myList.add('peach',786);
alert(myList.iterate());
/*=>output:
orange: 123
banana: 4
apple: 567
peach: 786
*/
or: alert(myList.iterate(1));
/*=>output:
apple: 567
banana: 4
orange: 123
peach: 786
*/
Upvotes: 7
Reputation: 75862
A simple encapsulation:
function Dictionary(p)
{
if(!this.Add)
{
Dictionary.prototype.Add = function(a)
{
if(!a.length) {a = [a];}
for(var i = 0, n=a.length; i<n; i++)
{
for(x in a[i])
{
this[x] = a[i][x];
this.keys.push(x);
}
}
}
}
this.keys = [];
if(typeof(p)!='undefined') {this.Add(p);}
}
var a = new Dictionary({'orange':123, 'banana':4, 'apple':567});
alert(a.keys);//returns [orange,banana,apple]
alert(a.keys[0]);//returns orange
alert(a.orange) //returns 123
a.Add({'mango':88}); //another way to add data
a.Add([{kiwi:16},{grapefruit:79}]) //another way to add data
alert(a.keys);//returns [orange,banana,apple,mango,kiwi,grapefruit]
Upvotes: 2
Reputation: 827792
You can do it in different ways:
var a = {'orange':123, 'banana':4, 'apple':567};
var b = new Object();
b['orange'] = 123;
b['banana'] = 4;
b['apple'] = 567;
var c = new Object();
c.orange = 123;
c.banana = 4;
c.apple = 567;
The syntax is different but internally the three declarations are equivalent.
Upvotes: 1
Reputation: 212088
Both of your assumptions are correct. Object literals are not guaranteed to return keys in any order.
The only way to do this without spinning your own type is to maintain an ordered list of keys:
var obj = {
orange:123,
banana:4,
apple:567
}
var keys = ['orange', 'banana', 'apple'];
for (var i=0; i<keys.length; i++){
value = obj[keys[i]]];
}
Ugly, I know.
Upvotes: 2