在JavaScript中' this '关键字让你感到困惑了吗?

4

我已经很久没有使用JavaScript了,今天正在重新学习它。总有一件事情让我感到困惑,那就是this关键字。我知道在jQuery事件处理程序中,比如click事件,this指的是触发事件的元素。即使我的函数没有参数,this如何传递给我作为回调函数的函数?

考虑以下代码:

$("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);
        }
    }
});

我正在尝试弄清楚如何将类名为SummaryTbRow的表格行元素传递给我的setTimeout回调函数。jQuery是否以类似于我使用匿名回调函数的方式传递this?在函数内部,我的this是否指向我传递的this

我知道我可以这样做:

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

但是我想弄清楚jQuery是如何将this传递给我的回调函数的,即使我的函数不需要参数。


jQuery使用.call/.apply来调用回调函数,这使您可以保持上下文。 - Selvakumar Arumugam
4个回答

3
为回答你的最后一个问题,在JavaScript中,你可以使用例如call将所选接收器传递给函数:
someFunction.call(someObject);

someFunction 函数内部,this 将指向 someObject

在你的情况下,你似乎想要的是:

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); 

我明白了,这解决了很多问题。我没有意识到调用的存在。我将不得不利用它。 - Justin
你很少需要直接使用 callbind。对于大多数标准的 jQuery 使用,你可以简单地将变量嵌入到闭包中(参见我的最后一个示例)。 - Denys Séguret

2
简短回答:
您可以通过使用函数的 .call().apply() 方法在函数上设置 this
详细回答:
在任何函数中,this 变量类似于 arguments 变量(这可能是您不知道的内容)。它在函数被调用时设置,并且是函数调用方式的产物。为了解释清楚,让我先以一个 arguments 的演示来开始。例如:
myFunction = function () {
    return arguments.length;
};

现在让我们看一下对myFunction的两个调用:
myFunction(); //is 0
myFunction(null); //is 1
myFunction(undefined); //is 1
myFunction(0, 0, 0, 0, 0); //is 5

正如您所看到的,arguments.length的值不取决于我们如何编写函数,而是取决于我们如何调用该函数。 this变量(也称为“调用对象”)也是如此。设置调用对象有三种方法(在ES5中有一种类似第四种的方法,但我们将忽略它):
  1. 通过使用点表示法调用函数来设置它(例如:something.myFunction()
  2. 通过使用函数的.call().apply()方法来设置它(例如:myFunction.call(someObject)
  3. 如果没有使用方法#1或#2进行设置,则默认为全局对象(例如:window
因此,大多数人习惯于使用方法#1。如果您将函数分配为对象的属性,然后使用对象和点表示法调用该函数,则该对象将被设置为this。就像这样:
var myFn = (function () { return this.x });

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

myObj.myFn(); //is 1

但如果myFn不是我们想要调用它的对象的属性,而是该对象遵循myFn可以处理它的正确形式(参见:鸭子类型),我们也可以使用方法2:

var myOtherObj = {
    x: 2
}

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

很酷,是吧?这就是jQuery的实现方式。当它们执行您的回调时,使用.apply(event.target)(将this设置为事件的目标对象)。由于他们的callbacks框架,他们以更复杂的方式执行,但思想在那里
无论如何,如果我不解释第三种方法,有些人会非常疯狂:如果不设置调用对象会发生什么?
由于所有全局变量都是全局对象的隐式属性,所以通过第三种方法可以获得一些有趣的效果。例如:
var x = 4;
myFn(); //is 4

但大多数情况下,您的全局对象未能满足函数对其调用对象的要求,因此通常会导致错误和许多挫败感。

可能比您想要的更详细,但希望现在您对调用对象及其狡猾的方法有了更多了解。


糟糕,又被接受了其他答案。这就是我花了15分钟提供详细答案、引用来源并提供完整解释的结果。哎,算了。 - Pete
我等了一会儿你 Pete。我不确定你是否还在做这件事。你确实更详细地讲解了 jQuery 是如何实现的,提供了更多相关信息。 - Justin

1

您可以使用fn.callfn.apply来调用函数,两者都需要一个上下文参数,该参数用于指定this


0

应用, 调用绑定方法用于此目的。在您的情况下,您只需编写:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接