JavaScript dictionaries: use hasOwnProperty, set __proto__ to null, or use ES proxies?

Siddharth Agarwal sid at mozillamessaging.com
Fri Dec 10 12:46:46 UTC 2010


JavaScript has several builtin methods defined on Object.prototype, 
including "toString", "toSource" and "watch". This means that all 
objects automatically inherit these properties, and that a check like 
("toString" in {}) always returns true.

This clearly causes unexpected behaviour for objects used as 
dictionaries, and is what caused bug 609941 [1]. There are very likely 
more such bugs lurking in our code. To be precise, any dictionary
(i) where the keys are arbitrary and determined by user input, and
(ii) where we care about membership in the dictionary (and not just 
iteration over all keys and values)
will have this bug.

There are a few ways out of this:
(a) Use hasOwnProperty [2] instead of "in" everywhere we want to test 
membership.
(b) Set __proto__ [3] to null at dictionary creation time.
(c) Similar to (b), define a Dict constructor and set its prototype to 
{__proto__: null}. Then create dictionaries with new Dict() instead of {}.
(d) Building on (c), use ECMAScript proxies [4] for Dict to get better 
semantics.

(a) is nicer than (b) and (c) from a language spec point of view; 
however, the "in" syntax is rather neat and intuitive, and we use it in 
a lot of places [5]. For (b) and (c), __proto__ is non-standard and 
deprecated, but it has the advantage of preserving the "in" syntax. The 
main problem, however, is that they lead to more unexpected behaviour: 
since toString isn't in the prototype any more, common idioms like 
Components.utils.reportError(dict) will throw an exception. (d) done 
right can resolve all these problems, but is only available in Gecko 
2.0, and I believe we need to fix bug 609941 in 1.9.2 as well.

Whatever we pick, I propose that to be on the safe side we use it across 
the board for all new dictionaries, and not just those that satisfy (i) 
and (ii) above. I also propose that code reviewers enforce this.

Sid

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=609941
[2] 
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
[3] 
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/proto
[4] http://wiki.ecmascript.org/doku.php?id=harmony:proxies
[5] A probably incomplete list is at http://bit.ly/gOF5jV



More information about the tb-planning mailing list