Overriding Map/etc with get/set hooks?

David Bruant bruant.d at gmail.com
Tue May 21 04:02:43 PDT 2013


Le 21/05/2013 04:06, Tab Atkins Jr. a écrit :
> For the CSS Variables spec I need to define an object with arbitrary
> string keys, with the initial set determined by the custom properties
> set in the style rule, and on modification I need to coerce the
> provided key to a string, and then go mutate the style rule
> accordingly.  When the style rule is mutated to add/remove custom
> properties, I also need to mutate the exposed keys on the object.  (In
> other words, this object has a bidirectional link with a style rule;
> it just exposes a more convenient and specialized interface for custom
> properties specifically.)
This description ("arbitrary string keys", "bidirectional link with 
style rule") suggests that you want a proxy (canonical values are in the 
style rule, the proxy is just a façade with a bit of validation/coercion 
logic). That's the sort of use case they've been introduced for.

> Right now I'm defining this via the WebIDL getter/setter/etc hooks,
> which ends up defining an "object map".  This is bad practice, though,
> because anything set on the prototype chain will show up as a
> (non-own) key, potentially causing confusion.
>
> I'd like to convert this over to an ES Map, as that avoids the above
> issue and gets me all the Map extras for free, which is nice.
Which exactly?
Of all the Map extras, I only see Map.p.clear() and Map.p.size that 
can't be done as easily with the base object interface (... well... size 
can be Object.keys().length)
Since keys are arbitrary, you'd have to invoke prototype methods through 
.call. Is it worth it?

> However, I don't think it's currently possible to do what I need.
>
> Is it possible add appropriate hooks to the ES spec to let me define
> the [[MapData]] via a spec, rather than as an initially-empty list of
> tuples that get/set unconditionally read from?  I need to be able to
> define in spec-ese that the [[MapData]] tuples consist of some list of
> data from a style rule, and that whenever a value gets set, I first
> coerce the key to a string, and then go mutate the style rule instead
> of the [[MapData]] (it then picks up the mutated data by virtue of
> being defined by the style rule).
>
> (One way to do this today is to subclass Map and provide my own
> get/set/etc. functions, but I need to override a potentially-open set
> (anything that doesn't directly lean on my overridden functions), and
> it doesn't prevent people from directly twiddling my [[MapData]] by
> calling Map.prototype.set.call() on my object.)
If you want to keep control over how people interact with your key/value 
interface, a proxy seems more appropriate. It's been designed so that 
you have full control and can't be bypassed.

Although the behavior Map.prototype.set.call(someProxy) isn't very clear 
yet spec-wise [1] you can be sure that it won't be possible to freely 
mess around an internal [[MapData]] (because it would open an undesired 
communication channel)

> Alternately: Proxies?
yup

David

[1] See "Non-generic built-in functions" under 
http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies#wrapping_irregular_objects


More information about the es-discuss mailing list