2012-03-27

Property Assignment and hasOwnProperty

An important task in JavaScript development is to check if a property has already been assigned a value. There are two ways to check for the presence of a property in an object. The first method, prop in obj, checks the existence of the property in the object or in its prototype chain. The second method, obj.hasOwnProperty(prop), checks if the property exists on the object itself.

If a property exists on the object’s prototype, it is masked by an assignment of that property on the object itself. Consider the following code snippet:

(function () {
 var p = {
  name : "human",
 };
 var a = Object.create(p);
 console.log(a.name); // human
 console.log(a.hasOwnProperty("name")); // false
 a.name = "Ali";
 console.log(a.name); // Ali
 console.log(a.hasOwnProperty("name")); // true
})();

Noting these results, it would seem appropriate to use hasOwnProperty as a test for checking whether the property has been assigned a value on the object proper. But this leads to an unexpected result in the particular case of “accessor” properties:

(function () {
 var p = Object.defineProperties({
   _age : 0,
  }, {
   _age : {
    enumerable : false,
   },
   age : {
    get : function () {
     return this._age;
    },
    set : function (age) {
     if (isNaN(age) || (age < 0)) {
      throw new Error("Invalid value for age: " + age);
     }
     this._age = age;
    },
    enumerable : true,
    configurable : true,
   },
  });
 var a = Object.create(p);
 console.log(a.age); // 0
 console.log(a.hasOwnProperty("age")); // false
 a.age = 14;
 console.log(a.age); // 14
 console.log(a.hasOwnProperty("age")); // false
})();

This example shows that “accessor” properties of the prototype are not masked by value assignment on the descendent object. Consequently, hasOwnProperty cannot detect value assignment in these cases.