26 May, 2009

JavaScript associative arrays.

JavaScript does not have a distinct "hash" type: all objects are hashes, including arrays, functions, etc. Due to this extreme flexibility, most people can get by without ever needing a so-called "associative array."

The problem with objects being hashes is that it tends to "break" the for-in loop. If you add a property to the prototype chain of an object, it will be enumerated in for-in loops. You can, of course, use an if statement to filter out the prototype chain, but this is cumbersome.

Enter the Hash constructor. I personally have never had need for a genuine hash, but I had fun making this, and hope it's useful for somebody. My goal was to implement a simple and lightweight system that would make use of closures and interfaces.

You initialize it with new Hash(), and you can pass along an object as a shorthand.

var hash = new Hash();
hash.key("test", "Hi!");

Is the same as:

var hash = new Hash({
    test: "Hi!"
});

Each instance of the Hash constructor has it's own private variable values, which you cannot touch. Instead, you use the key() method to read, write, and delete values. It works like this:

hash.key("test");
// Get the value of the key "test"

hash.key("test", "Hi!");
// Set the value of the key "test"

hash.key("test", null);
// Delete the value of the key "test"

If you specify only one argument, it will return the value in the key. If you specify two arguments, it will set the value of the key. If you set a key to the value null, it will delete the key, so it no longer exists.

In addition, every Hash instance has a length property (like an array) that will tell you how many keys are in the hash. You are free to set this property to whatever you want (or even delete it), but it will have no effect. The actual length is a private variable; so next time you set or delete a key, the length property will be overwritten with the correct length.

This is all very nice, of course, but I went a step further: a forEach() method. This method will loop over the keys in the hash, and run the function you specify on each one. The two arguments it passes are the name and value of the key. In addition, this is bound to the current hash, making it easy to manipulate the keys.

Here's an example of a simple way to delete all the keys in a hash:

hash.forEach(function (name) {
    this.key(name, null);
});

And here's a way to obtain the name and value of all the keys in a hash:

hash.forEach(function (name, value) {
    alert("Key " + name + " has the value: " + value);
});

[LINK] The source code.
[LINK] The unit tests.

No comments:

Post a Comment