2

I need something of a HashMap in javascript. Can we do this:

var map = {};
map['foo'] = true;
map['zoo'] = true;
...

if (map['foo']) {
    // yes, foo exists.
}
else {
    // no, foo does not exist.
}

how do we properly check for the existence of the property without inserting it if it does not exist? For example, I don't want map.foo to exist after the above check if I didn't explicitly add it,

Thanks

0

3 Answers 3

9

In your example, checking for:

if (map['foo']) {
  //..
}

Not only checks if the property is not defined on the object, the condition expression of the if statement will evaluate to false also if the property holds a value that coerces to false on boolean context (aka falsy values), such as 0, NaN, an empty string, null, undefined and of course false, e.g.:

var map = {
  'foo': 0 // or any other falsy value
}; 

if (map['foo']) {
  // foo is truthy...
} else {
  // foo is falsy or not defined
}

To check if a property exist on an object, regardless its value -which can be falsy, even undefined- , you can use the hasOwnProperty method, for example:

var map = {};
map['foo'] = 0;

if (map.hasOwnProperty('foo')) {
  // foo exist physically on the object...
}

The only problem with this method is that if someone adds a property named hasOwnProperty to an object, it wont work, for example:

var obj = {
    hasOwnProperty: 'bar'
};

If you execute obj.hasOwnProperty('prop'), it will give you a TypeError, because the object contains a string property that shadows the method -invoking the string would cause the error-.

A workaround to this is to call the hasOwnProperty method directly from the Object.prototype object, for example:

if (Object.prototype.hasOwnProperty.call(obj, 'prop')) {
  //..
}

You can also use the in operator:

if ('prop' in obj) {
  //...
}

The difference with the first method is that the in operator checks also for inherited properties, for example:

var obj = {};
obj.hasOwnProperty('toString'); // false
'toString' in obj; // true, inherited from Object.prototype.toString

See also:

Edit:

Extending my response to the @slebetman comment, about checking if (map.foo !== undefined).

As I was commenting, there are some concerns about accessing the undefined global property and also a semantic difference between checking a property value vs. property existence.

The undefined global property is not defined as read-only ECMAScript 3rd Edition Standard, (is now writable = false on ES5 :)

In almost all implementations its value can be replaced.

If someone makes:

window.undefined = 'foo';

// It will break your code:
var obj = {};
if (obj.foo !== undefined) {
  alert("This shouldn't ever happen!");
}

Also the semantic difference: by testing if map.foo !== undefined we are not technically only checking if the property exist on the object or not, a property can exist, holding undefined as a value, for example:

var map = {
  'foo': undefined
};

map.hasOwnProperty('foo'); // true, because the property exists although
                           //       it holds the undefined value
map.foo !== undefined;     // false
Sign up to request clarification or add additional context in comments.

5 Comments

For empty objects created directly from the Object object (which is true in this case) using hasOwnProperty is not necessary. Just directly check if the value is undefined: if (map.foo !== undefined).
@slebetman, yes but there are some concerns about accessing the undefined global property as an identifier, 1. Is not part of ECMAScript 3, (now is defined on ES5 :), 2. In some implementations the property is not read-only, its value can be replaced, e.g. if someone makes window.undefined = true;, it will break your code. Also checking map.foo !== undefined we are not technically checking if the property exist on the object or not, a property can exist, holding undefined as a value.
@slebetman — Also consider modifications to Object.prototype. Try this in your browser: javascript:Object.prototype.foo=5;bar={};alert((bar.foo!==undefined)+","+bar.hasOwnProperty("foo"));Object.prototype.hasOwnProperty=function(){return true};alert(bar.hasOwnProperty("baz"))
CMS: the undefined property of the global object is in ECMAScript 3. It's not specified as being read-only, so it can be replaced in all implementations I'm aware of. The change in ES5 is to make it read-only.
@Tim, yes sorry, -15.1.1.3- the only implementations where it is read-only at the moment, are the latest betas of Firefox 4, and the IE9 Platform Previews. Thanks!
0

By using JavaScript Hashmap Equivalent

<html>
<head>
<script>
HashMap = function(){
  this._dict = {};
}
HashMap.prototype._shared = {id: 1};
HashMap.prototype.put = function put(key, value){
  if(typeof key == "object"){
    if(!key.hasOwnProperty._id){
      key.hasOwnProperty = function(key){
        return Object.prototype.hasOwnProperty.call(this, key);
      }
      key.hasOwnProperty._id = this._shared.id++;
    }
    this._dict[key.hasOwnProperty._id] = value;
  }else{
    this._dict[key] = value;
  }
  return this; // for chaining
}
HashMap.prototype.get = function get(key){
  if(typeof key == "object"){
    return this._dict[key.hasOwnProperty._id];
  }
  return this._dict[key];
}


var color = {}; // unique object instance
var shape = {}; // unique object instance
var map = new HashMap();
map.put(color, "blue");
map.put(shape, "round");
console.log("Item is", map.get(color), "and", map.get(shape));
</script>

<head>
<body>
<script>document.write("Existing Item Testing :\t\t\t" + map.get(color)+"
"); document.write("Non - Existing Item Testing :\t\t\t" + map.get("test")+ ""); </body> </html>

Output:

Existing Item Testing : blue
Non - Existing Item Testing : undefined 

Comments

0

Java Map and Java HashMap are different things. Java Map is a hash table that has key labeled values, and a fast search of values by keys. HashMap on the other hand has the same seak time if you search value by key or key by value.

I wrote a similar data structure to Java Map, but I am still developing the HashMap class for javascript and I will share it as soon as I can. Note that my solution is just a wrapper to the native hash table, for easier use and iteration. A bit slower put and remove times, and a bit more of memory.

You can check it out on my blog, cause it is too long for here: http://stamat.wordpress.com/javascript-map-class/

Thanks for giving it a chance! Feedback is very appreciated! :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.