简体   繁体   中英

Confused about the 'this' keyword in javascript

I haven't used Javascript in a long time and have been refreshing myself on it today. One thing that always got me was the this keyword. I know in jQuery event handlers, such as the click event, this refers to the element that fired the event. How is this passed to the function that I give it as a callback even though my function has no arguments?

Given the following code:

$("tr.SummaryTbRow").data("Animating", false);
$("tr.SummaryTbAltRow").data("Animating", false);

$("tr.SummaryTbRow").click(function () {
    if ($(this).data("Animating") == false) {
        if ($(this).next(".Graph").css("display") == "none") {
            $(this).data("Animating", true);

            //Part I am questioning.
            setTimeout(function () {
                $(this).data("Animating", false);
            }(this), 550);

            $(this).next(".Graph").slideRow('down', 500);
        }
        else {
            $(this).data("Animating", true);
            $(this).next(".Graph").slideRow('up', 500);
        }
    }
});

I am trying to figure out how to pass the element table row with class SummaryTbRow to my setTimeout call back function. Does jQuery pass this in a similar fasion to what I am doing with my anonymous call back function? Does my this inside the function refer to the this I pass in?

I know I could just do:

setTimeout(function (element) {
    $(element).data("Animating", false);
}(this), 550);

But I want to figure out how jQuery is able to pass this to my call back function even though my function takes 0 arguments.

To answer you last question, you may pass the receiver of your choice to a function in javascript using for exemple call :

someFunction.call(someObject);

Inside someFunction , this will be someObject .

In your case, what you seem to want is

setTimeout(function (element) {
    $(element).data("Animating", false);
}, 550, this); // this will be passed as element to the callback

or ( more compatible )

var _this = this;
setTimeout(function () {
    $(_this).data("Animating", false);
}, 550); 

Short answer:

You can set this on a function by using the function's .call() and .apply() methods.

Long answer:

The this variable on any function is similar to the arguments variable (which is probably something you didn't know about). It's set when the function is called and is an artifact of how the function is called. To explain, let me start with a demonstration of arguments . Consider:

myFunction = function () {
    return arguments.length;
};

Now let's look at a couple calls to myFunction :

myFunction(); //is 0
myFunction(null); //is 1
myFunction(undefined); //is 1
myFunction(0, 0, 0, 0, 0); //is 5

As you can see, the value of arguments.length is not dependent on how or where we wrote the function, but on how we called the function. The same is true of the this variable (otherwise known as the "calling object"). There are exactly 3 methods for setting the calling object (there's a sort-of 4th in ES5, but we'll ignore that):

  1. You can set it by calling the function using dot-notation (eg something.myFunction() )
  2. You can set it by using the function's .call() or .apply() methods (eg myFunction.call(someObject) )
  3. If it's not set using method #1 or #2, it will default to the global object (eg window )

So most people are used to method #1. If you assign your function as a property of an object, then call the function using the object and dot-notation, then the object gets set as this . Like so:

var myFn = (function () { return this.x });

var myObj = {
    x: 1,
    y: myFn
};

myObj.myFn(); //is 1

But we can also use method 2 if myFn isn't a property of the object we want to call it on but the object follows the correct form for myFn to be able to act on it (see: duck typing):

var myOtherObj = {
    x: 2
}

myFn.call(myOtherObj); //is 2
myFn.apply(myOtherObj); //is 2
myFn.apply({ x : 3}); //is 3

Pretty cool, eh? This is how jQuery does it. When they execute your callback, they do so using .apply(event.target) (setting this to the event's target object). They do it in a more complex manner because of their callbacks framework, but the idea is there .

Anyway, I wouldn't be offering a long answer if I didn't toss in an explanation of method #3, which drives some people totally insane: What happens if you don't set the calling object?

Because all global variables are implicit properties of the global object, you get some interesting effects from method #3. Such as:

var x = 4;
myFn(); //is 4

But most of the time you're not lucky enough to have your global object meet the requirements the function has for its calling object, so usually it just results in an error and a lot of frustration.

Probably more than you were looking for, but hopefully you're now much more informed on the calling object and its wily ways.

您可以使用fn.callfn.apply调用函数,这两个函数都带有用于this的上下文参数。

Apply , call and bind methods serve for that purpose. In your case you just write:

setTimeout(function() {
  $(this).data("Animating", false);
}.bind(this), 550);

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