jsdict
jsdict copied to clipboard
Dictionaries using ECMAScript proxies
A safe JavaScript dictionary
The problem
JavaScript objects used as dictionaries cannot support arbitrary keys. The following snippets of code, run in the SpiderMonkey JavaScript shell, demonstrate the problem:
js> var foo = {}
js> "toString" in foo
true
Here toString is in foo's prototype, so we unexpectedly return true. This
can be solved by using hasOwnProperty wherever we would normally use in, but that is ugly and cumbersome.
js> var bar = {}
js> bar["__proto__"] = "test"
js> for (var k in bar) print(k)
(no output)
SpiderMonkey treats the `__proto__` property of an object specially and does
not consider it enumerable. Since __proto__ is non-configurable, there's no
non-fragile way to solve this that I know of. (Setting __proto__ to null seems
to work but is probably fragile.)
The solution
-
Define a Dict constructor, instances of which are safe dictionaries.
-
Use objects under the hood for efficient lookup, and use a reversible conversion to avoid colliding with special objects.
-
Use ECMAScript proxies to allow (... in ...) and for (... in ...) to function as expected.
Unfortunately we cannot use direct property accesses, because there's no way to distinguish between toString called because JavaScript wants to coerce our object into a string and toString read as a key. Virtual Values for Language Extensions, if implemented in Harmony, might be able to solve this, but I'm not sure.
Limitations
-
This is (obviously) a fair bit slower than direct property access.
-
We only support strings and numbers (and things that can be coerced to strings or numbers) as keys.