简体   繁体   中英

this is bound incorrectly if jquery function is called from a stored variable

I'm calling a jQuery function in two ways, one works the other doesn't because this is bound incorrectly.

$('#my-div').fadeOut();

works as expected, the value of this inside the fadeOut function is the jQuery object.

var fadeOutFn = $('#my-div').fadeOut;
fadeOutFn();

doesn't work since value of this is now Window

here is the jsfiddle with both examples.

http://jsfiddle.net/XCAdP/

Edit: Adding some clarifications on why I posted the question, I don't really want to know how to fix this. that's not the issue. I want to understand why it's happening.

Yes it does not know the element it is applying fadeOut animation to and this context will be mostly the window and not the jquery object in this case. You can pass the context using function.call

Try this:

var fadeOutFn = $('#my-div').fadeOut;
fadeOutFn.call($('#my-div'));

Or just do this:

use function.bind to bind the context to the function reference, and invoke it.

var fadeOutFn = $().fadeOut.bind($('#my-div'));
fadeOutFn();

Read function.bind

For non supported browsers you can add this in your js file for support as mentioned in the document:

if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
      // closest thing possible to the ECMAScript 5 internal IsCallable function
      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var aArgs = Array.prototype.slice.call(arguments, 1), 
        fToBind = this, 
        fNOP = function () {},
        fBound = function () {
          return fToBind.apply(this instanceof fNOP && oThis
                                 ? this
                                 : oThis,
                               aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();

    return fBound;
  };
}

Yes, when you get a method as a function reference, you disconnect it from the object. A function only works as a method when you call it in the context of an object, which is usually done with the . operator, eg obj.method() .

If you call a function without the context of an object, it's called with the global scope as context, ie the window object. Example:

var obj = {
  name: "obj",
  method: function() { alert(this.name); }
};

obj.method(); // shows the name "obj"
var m = obj.method;
m(); // shows the name of window
m.call(obj); // shows the name "obj"

var obj2 = {
  name: "obj2"
};
m.call(obj2); // shows the name "obj2" (using the method from obj)

If you want to make it work as a method, you have to call it with the object as context:

var obj = $('#my-div');
var fadeOutFn = obj.fadeOut;
fadeOutFn.call(obj);

You can use the proxy method to make a function that calls the function with the correct context:

var obj = $('#my-div');
var fadeOutFn = $.proxy(obj.fadeOut, obj);
fadeOutFn();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM