Javascript 回调中的 `this` 和作用域

`this` and scope in Javascript callback

我直接展示代码:

disable: function(e){
    that = this;
    var haha = this;
    $.post(url, function(){
        console.log(this);// (why ajax object here?
        console.log(that);// (I understand this one works
        console.log(haha);// ReferenceError 
    })
}

我在这里感到困惑的是:

  1. 为什么回调中的this不引用外部?我认为回调中的this遵循默认的绑定角色。
  2. 为什么haha不是指that呢?我认为当在本地范围内找不到 haha 时,它将转到外部范围。

我知道使用 that 不是一个好方法。这就是我尝试 haha 但失败的原因。

我认为您正在尝试从控制台访问这些值...在这种情况下,haha 将不起作用,因为它是函数的本地值,而您已将 that 创建为全局变量(因为没有使用 var)。

但这是一个错误的模式,因为某些其他脚本可能会在 ajax 请求完成之前修改 that 的值。

回调函数在它自己的不同范围内运行,因此 this 指的是它,而不是它定义的地方。您可以使用绑定或应用或调用函数来绑定它。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

所以 this 指的是别的东西,但是因为它是在函数声明的范围内声明的,所以它仍然存在。

问题 1 的答案是:因为您可以在 Javascript 中随意重新绑定它,而 jQuery 恰好适用于 jQuery.post(),如 the documentation for jQuery.ajax() 所述:

The this reference within all callbacks is the object in the context option passed to $.ajax in the settings; if context is not specified, this is a reference to the Ajax settings themselves.

通常:您可能永远不应该依赖 Javascript 库来 而不是 重新绑定 this。如果您在嵌套回调中需要它的值,只需保存它。在不同名称的变量中,或使用 Function.bind():

$(function() {
    var self = this;
    $.post("/echo/json/", (function() {
        console.log("self", self); // this will be the document itself
        console.log("this", this); // as will self
        console.log("self === this", self === this); // should output true
    }).bind(this));
});

jsFiddle 示例:https://jsfiddle.net/millimoose/Lx2oxobg/。对于它的价值,我强烈更喜欢使用单独的变量来提高可读性,因为你可以给它一个描述性的名称,而且 this 不是反弹的事实,而且您已经有效地重新分配了回调的一个参数,并没有一直隐藏 块之后 这适用于此。

关于你的问题2,我无法重现,请看我的第二个fiddle:https://jsfiddle.net/millimoose/zL352rzf/。正如其他人所说,根据您的屏幕截图,您可能实际上并没有从 console.log() 本身获得 ReferenceError

尝试使用 $.ajax()context 选项设置 successthiserror 回调

disable: function(e) {
    $.ajax({
      context: this
      , type:"POST"
      , url:url 
      , success: function() {
          console.log(this);
        }
      , error: function() {
          console.log(this)
        }
    })
}