Answer in 2010: (see below for a 2013 update)
No, you can't redirect property name lookups to your own function.
However, as of ECMAScript5, you can define properties with "getters" and "setters". This is a new feature which isn't widely-supported yet, but when it is, it will do something vaguely similar. This is covered in a couple of parts of the spec. So if you defined all of your properties that way, and then sent the actual request to your central getValue
function, you'd end up with largely what you wanted. Someday. :-) Except that it won't call getValue
for a property that doesn't exist.
Answer in 2013:
This is going to change soon (and it already has for up-to-date Firefox users): ECMAScript 6th edition will have proxies. They're defined in the draft specification, and also on this page (but the spec drafts take precedence).
Proxies let you create objects that are true proxies (facades) for other objects. Here's a simple example that turns any property values that are strings to all 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"
Live Example | Source
Operations you don't override have their default behavior. In the above, all we override is get
, but there's a whole list of operations you can hook into.
In the get
handler function's arguments list:
target
is the object being proxied (original
, in our case).
name
is (of course) the name of the property being retrieved.
receiver
is either the proxy itself or something that inherits from it. In our case, receiver
is ===
proxy
, but if proxy
were used as a prototype, receiver
could be a descendant object, hence it being on the function signature (but at the end, so you can readily leave it off if, as with our example above, you don't actually use it).
This lets you create an object with the catch-all getter and setter feature you 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;
}
});
console.log("[before] obj.foo = " + obj.foo);
obj.foo = "bar";
console.log("[after] obj.foo = " + obj.foo);
Live Example | Source (Note how I've left receiver
off the functions, since we don't use it. receiver
is an optional fourth arg on set
.)
The output of the 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 we get the "non-existant" message when we try to retrieve foo
when it doesn't yet exist, and again when we create it, but not subsequently.