开发者

Javascript, callback when object's attributes change?

Functions in javascript are objects:

var x = function(){};
x.y = 1;
console.log(x.y); //Prints 1

Is there any way to call a function when y changes?

My reason for doing this is that I'm trying to override jquery's "$" function so that I can 开发者_JAVA百科benchmark performance. It works fine when the JS runs $('mySelector'). However, plugins that are created using $.fn.myPlugin will change the attributes in the object I overrided, rather than the original.


I believe what you're looking for are JavaScript setters. Be careful to study browser support tough.

The following example is from the MDN documentation. First, when you create your own objects:

var o = {a: 7,
         get b() {return this.a + 1;},
         set c(x) {this.a = x / 2}};

Second, when you augment an existing prototype:

var d = Date.prototype;
d.__defineGetter__("year", function() { return this.getFullYear(); });
d.__defineSetter__("year", function(y) { this.setFullYear(y); });


There is no way to do this that will work in all browsers. Getters and setters are nice, but are completely useless when you have to support IE6 or IE7.


The approach I settled on used bandi's defineGetter suggestion, but looped through the attributes of the original object.

getAttr = function(att) {
    return function() { return eval("originalObject."+att) };
}
//Delegate all attribute access to original object
for (var att in originalObject) {
    overRiddenObject.__defineGetter__(att.toString(), getAttr(att));
}

And here is the full snippet that I can stick in my code to profile jQuery selectors:

var original$ = $;
$ = function() {
    //Ignore document.ready function calls
    if (typeof(arguments)[0] === 'function') {
        return original$.apply( this, arguments );
    }

    t1 = new  Date().getTime(); 
    // Run each selector 100 times since we can only time it to the millisecond
    for (var i=0; i<100; i++)
        x = original$.apply( this, arguments );
    t = new Date().getTime()-t1;
    // Print selector name, time taken and number of elements matched
    console.log(arguments," "+t+"ms"+" ("+x.length+" element(s))");
    return x;
};
getAttr = function(att) {
    return function() { return eval("original$."+att) };
}
//Delegate all attribute access to original object
for (var att in original$) {
    $.__defineGetter__(att.toString(), getAttr(att));
}

It could probably be done with better style using closure's, but it works.

Also it will only work on jQuery plugins when you remove the "$" from (function($) {...))(jQUery).

This could be worked around by rewriting this to use .extend and override methods that are called during selection - something I'm looking into to make this pluggable.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜