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, if proxy 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

Popular posts from this blog

c++ - OpenCV Error: Assertion failed <scn == 3 ::scn == 4> in unknown function, -

php - render data via PDO::FETCH_FUNC vs loop -

The canvas has been tainted by cross-origin data in chrome only -