3

This is related to, but not a duplicate of, another SO Q&A Override jQuery functions.

It is clear from the answer to the above question that the pattern to override a jQuery function is:

(function($){

    // store original reference to the method
    var _old = $.fn.method;

    $.fn.method = function(arg1,arg2){

        if ( ... condition ... ) {
           return  ....
        } else {           // do the default
           return _old.apply(this,arguments);
        }
    };
})(jQuery);

But why!?

I've been able to override a jQuery function simply by defining a function of the same name as the function to be overridden, within $.extend or $.fn.extend.

Consider this:

// random example showing jquery function overriding
$.fn.extend({
    hide: function() {
        $(this).css({"color":"red"});
    }
});

$("#test").hide(); // this will actually paint the #test element red!

jsFiddle

I'd like to understand why _old.apply(this,arguments) would be the preferred way to override a jQuery function, as listed here and here.

Community
  • 1
  • 1
SNag
  • 17,681
  • 10
  • 54
  • 69
  • 1
    So what's the problem you're having? – Popnoodles May 31 '14 at 12:54
  • `fn` is jQuery's shortcut for `prototype`, so you can just do `$.fn.hide` (or `$.prototype.hide`) to create a new prototyped property called `hide` that overrides the previous `hide`, and to understand that you should probably head over to MDN and read about objects and prototypes, as this has little to do with jQuery. – adeneo May 31 '14 at 12:58
  • The problem is that I'm missing the piece that justifies why `.apply` would be the preferred way to override a jQuery function. – SNag May 31 '14 at 13:04
  • Obviously the jQuery arguments, are provided in array. Instead of overriding I would use middle man: http://tech.zumba.com/middleman.js/ – kidwon May 31 '14 at 13:06

2 Answers2

2
(function($){

    // store original reference to the method
    // stored locally
    var _old = $.fn.method;

    $.fn.method = function(arg1,arg2){

        if ( ... condition ... ) {
           return  ....
        } else {           // do the default
           // call apply method, in order to pass the this context.
           return _old.apply(this,arguments);
        }
    };
})(jQuery);

Here in the above code, we are calling an anonymous function, in which we are declaring a local variable _old. When this anonymous function execute, it save the _old method reference and form a closure. Now, when we call the new method, i.e,

    $.fn.method = function(arg1,arg2){
       if ( ... condition ... ) {
           return  ....
        } else {           // do the default
           return _old.apply(this,arguments);
        }
    };

we also have an access to _old method, since its scope exists in the current context. And then, we can use it inside the new method.

Here we are calling _old method with the help of apply, because we want to have the same this context for that as well.

With this approach, we can easily override the jQuery method by preserving its original functionality.

Mohit Pandey
  • 3,679
  • 7
  • 26
  • 38
1

From glancing at references provided at original post, summary of pattern could be to keep both "old" and "new" methods available ?

Edit, updated

Sorry, I don't get this. As far as I see, the reference to the overridden method is saved in a local variable in a closure is unquestionably lost outside the closure. Can you explain how the "old" method is still available? –SNag

I'd like to understand why _old.apply(this,arguments) would be the preferred way to override a jQuery function, as listed here and here.

Utilizing pattern at 1st link , above , if interpret pieces correctly, appear arguments test within if statement of jquery method within "self-executing anonymous function" determine return value of "old" or "new" (newly included; override) jquery method ?

i.e.g., try

html

<div>abc</div>

js

// See http://www.paulirish.com/2010/duck-punching-with-jquery/ , at
// `First we start off with a self-executing anonymous function,
// that makes a happy closure while remapping jQuery to $:`

// `closure` start
    (function ($) {
        // jquery `.css()`
        var _oldcss = $.fn.css;
        // jquery `.hide()`
        var _oldhide = $.fn.hide;

        // "new" `.css()`
        $.fn.css = function (prop, value) {
            // "new" `.css()` `test`
            if (/^background-?color$/i.test(prop) 
                && value.toLowerCase() === 'burnt sienna') {
                return _oldcss.call(this, prop, '#EA7E5D');
            } else {
                return _oldcss.apply(this, arguments);
            }
        };

        // "new" `.hide()`
        $.fn.hide = function (prop, value) {
            // "new" `.hide()` `test` 
            if (/color/i.test(prop) && /[a-f]|[0-9]/i.test(value)) {
                return $.fn.css.call(this, prop, value);
            } else {
                return _oldhide.apply(this, arguments);
            }
        };
    })(jQuery);
    // `closure` stop

    // and using it...
    // "new" `.css()`
    jQuery(document.body).css('backgroundColor', 'burnt sienna');
    // "old" `.css()`
    $("div").css("color", "yellow");
    // "old" `.hide()`
    $("div").hide(7500, function () {
        // "old" `.css()`
        $(document.body)
            .css({
            "transition": "background 2s",
            "background": "#edd452"
        })
        .find($("div")).show(2500)
        // "new" `.hide()`
        .hide("color", "red")
    });

jsfiddle http://jsfiddle.net/guest271314/5bEe4/

guest271314
  • 1
  • 15
  • 104
  • 177
  • Sorry, I don't get this. As far as I see, the reference to the overridden method is saved in a local variable in a closure is unquestionably lost outside the closure. Can you explain how the "old" method is still available? – SNag May 31 '14 at 18:21
  • 1
    @SNag:Reference of a overridden method is saved in a local variable, which is available inside the anonymous function(thus form a closure). once you called new method, it will call the `_old` method( as its scope is still present). Here, `apply` is used to pass the original(current) `this` reference, so that its context is available on the `_old` method. The former way is used, because here you can override the method by preserving its original functionality, so that original `jQuery` functionality doesn't break. – Mohit Pandey Jun 02 '14 at 05:56
  • @MohitPandey: Your comment makes a lot of sense. If you could write out a complete answer, I'd be glad to accept it! Thanks! – SNag Jun 02 '14 at 11:46