Javascript overloading dot
Hi is there a way to overload the '.'(dot) and [] operator in javascript. ie if I say obj.Name or obj['Name'] it should call a common method in the obj class by passing Name as argument. The similar kind of functionality available in python using property method. But here I want the ".Name" to be passed as argument to the开发者_如何学Python common method.
like this..
function Data(){
this.getValue(name){
return '...'
}
}
data = new Data()
name = data.Name
name = data['Name']
//both should call data.getValue()
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 ifproxy
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.
On recent JS versions, there is indeed something similar to Python's properties.
Also see question Javascript getters and setters for dummies?
It may be enough for you, although Python is still way more flexible and compact.
Nope, you can't overload or replace it in JavaScript. I wish I had a more comprehensive/informational answer for you...but it just isn't possible, I guess there was never a need seen to add the ability.
As others have stated, this is impossible as operator overloading is impossible in ECMAscript.
If you really need to do this then I would use some preprocessing to convert the parts of code (and only those that really needs to be instrumented like this) into instrumented code.
This could easily be done using a little regexp like this
var a= "var a = b.c['foo']" // get this via xhr or something
var re = /(\[(.*)\])|(\.([\w\d]+)\b)/g;
var b = a.replace(re, function(m){
return ".get('" + m.replace(/[[\].'\"]/g,"") + "')";
});
b; // "var a = b.get('c').get('foo')"
eval(b);
精彩评论