metaprogramming - Is it possible to implement dynamic getters/setters in JavaScript? -
i aware of how create getters , setters properties names 1 knows, doing this:
// trivial example: function myobject(val){ this.count = 0; this.value = val; } myobject.prototype = { value(){ return this.count < 2 ? "go away" : this._value; }, set value(val){ this._value = val + (++this.count); } }; var = new myobject('foo'); alert(a.value); // --> "go away" a.value = 'bar'; alert(a.value); // --> "bar2"
now, question is, possible define sort of catch-all getters , setters these? i.e., create getters , setters property name isn't defined.
the concept possible in php using __get()
, __set()
magic methods (see the php documentation information on these), i'm asking there javascript equivalent these?
needless say, i'd ideally solution cross-browser compatible.
2013 , 2015 update (see below original answer 2011):
this changed of es2015 (aka "es6") specification: javascript has proxies. proxies let create objects true proxies (facades on) other objects. here's simple example turns property values strings caps on retrieval:
var original = { "foo": "bar" }; var proxy = new proxy(original, { get: function(target, name, receiver) { var rv = target[name]; if (typeof rv === "string") { rv = rv.touppercase(); } return rv; } }); console.log("original.foo = " + original.foo); // "bar" console.log("proxy.foo = " + proxy.foo); // "bar"
"use strict"; (function() { if (typeof proxy == "undefined") { console.log("this browser doesn't support proxy"); return; } var original = { "foo": "bar" }; var proxy = new proxy(original, { get: function(target, name, receiver) { var rv = target[name]; if (typeof rv === "string") { rv = rv.touppercase(); } return rv; } }); console.log("original.foo = " + original.foo); // "bar" console.log("proxy.foo = " + proxy.foo); // "bar" })();
operations don't override have default behavior. in above, override get
, there's whole list of operations can hook into.
in get
handler function's arguments list:
target
object being proxied (original
, in our case).name
(of course) name of property being retrieved.receiver
either proxy or inherits it. in our case,receiver
===
proxy
, ifproxy
used prototype,receiver
descendant object, hence being on function signature (but @ end, can readily leave off if, our example above, don't use it).
this lets create object catch-all getter , setter feature want:
var obj = new proxy({}, { get: function(target, name) { if (!(name in target)) { console.log("getting non-existant property '" + name + "'"); return undefined; } return target[name]; }, set: function(target, name, value) { if (!(name in target)) { console.log("setting non-existant property '" + name + "', initial value: " + value); } target[name] = value; return true; } }); console.log("[before] obj.foo = " + obj.foo); obj.foo = "bar"; console.log("[after] obj.foo = " + obj.foo);
"use strict"; (function() { if (typeof proxy == "undefined") { console.log("this browser doesn't support proxy"); return; } var obj = new proxy({}, { get: function(target, name) { if (!(name in target)) { console.log("getting non-existant property '" + name + "'"); return undefined; } return target[name]; }, set: function(target, name, value) { if (!(name in target)) { console.log("setting non-existant property '" + name + "', initial value: " + value); } target[name] = value; return true; } }); console.log("[before] obj.foo = " + obj.foo); obj.foo = "bar"; console.log("[after] obj.foo = " + obj.foo); })();
(note how i've left receiver
off functions, since don't use it. receiver
optional fourth arg on set
.)
the output of above is:
getting non-existant property 'foo' [before] obj.foo = undefined setting non-existant property 'foo', initial value: bar [after] obj.foo = bar
note how "non-existant" message when try retrieve foo
when doesn't yet exist, , again when create it, not subsequently.
answer 2011 (see above 2013 , 2015 updates):
no, javascript doesn't have catch-all property feature. accessor syntax you're using covered in section 11.1.5 of spec, , doesn't offer wildcard or that.
you could, of course, implement function it, i'm guessing don't want use f = obj.prop("foo");
rather f = obj.foo;
, obj.prop("foo", value);
rather obj.foo = value;
(which necessary function handle unknown properties).
fwiw, getter function (i didn't bother setter logic) this:
myobject.prototype.prop = function(propname) { if (propname in this) { // object or prototype has property, // return existing value. return this[propname]; } // ...catch-all, deal undefined property here... };
but again, can't imagine you'd want that, because of how changes how use object.
Comments
Post a Comment