【问题标题】:Accessing variable in callback function... what?在回调函数中访问变量...什么?
【发布时间】:2012-12-02 03:03:18
【问题描述】:

我浏览了很多帖子,终于得到了我需要的东西:

$("a.foo").click(function(){
    var that = this;
    jPrompt("Type something:","","", function(r) {
        $(that).text(r);
    }
}

来自以下内容: Accessing $(this) within a callback function

我想知道是否有人可以详细说明这里到底发生了什么(为什么 this 不重新分配就不能使用?)以及我应该阅读哪些核心信息?据我所知,这可能与闭包有关……这是我在四处搜索时遇到的大部分内容。准确吗?

就我而言,我希望执行一些代码,然后在 ajax 请求完成后重定向。在回调函数中,我正在运行 $(this).attr("href"),它返回未定义。

【问题讨论】:

标签: javascript jquery


【解决方案1】:

this 由 javascript 根据函数的调用方式分配。因此,当jPrompt() 调用回调时,jPrompt() 函数决定了this 在您的回调中的值。

因此,除非 jPrompt 通过您传入的某个参数竭尽全力为 this 保持相同的值,否则它可能具有不同的值。因此,您可以将其保存起来以便在回调中访问,就像您所做的那样。这是 javascript 回调中非常常见的设计模式。

仅供参考,this 的一些分配方式:

  • obj.method() - this 中的 method() 将设置为 obj
  • func.call(obj) - this in func() 将设置为 obj
  • func() - this 将在 func()undefined 严格模式下设置为 window

【讨论】:

    【解决方案2】:

    this 的含义会根据您所在的位置而有所不同。点击事件处理程序中的this 意味着传递给jPrompt 函数的回调中的this 以外的其他内容。

    对于它的价值,您不需要重新分配this,因为传递给您的处理程序的event 对象将引用currentTarget

    $("a.foo").on("click", function (event) {
        // 'this' here refers to the anchor we clicked
        jPrompt("Type something:", "", "", function (r) {
            // 'this' here refers to whatever jPrompt instructs
            $(event.currentTarget).text(r);
        }
    }
    

    【讨论】:

      【解决方案3】:

      问题中的代码添加了一些 cmets:

      $("a.foo").click(function(){
          var that = this; //`this` holds the a object clicked.  now so does `that`! 
          jPrompt("Type something:","","", function(r) { 
              //even if `this` has a different value here, `that` still holds the a object clicked
              $(that).text(r);
          }
      }
      

      这是您经常会发现自己在类似情况下所做的事情。 this 与上下文相关,您经常需要在一个上下文中保留 this 的值并在另一个上下文中使用它。

      ECMAScript 规范的引用:

      10.1.7 这个

      有一个 this 值与 每个活动的执行上下文。这 this 值取决于调用者和 正在执行的代码类型,并且是 当控制进入 执行上下文。

      希望能回答您的问题。您还要求提供进一步阅读的资源。请访问:

      https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this

      这些人提供了详细且通常非常准确的出色文档(与其他流行的参考资源不同,这些参考资源通常首先出现在 Google 搜索中——w3cshools.com 我在想你!)。

      【讨论】:

        【解决方案4】:

        this 的简要概述

        this 在 JavaScript 中是动态作用域。它的行为不同于所有其他词法范围的变量。其他变量没有不同的绑定,具体取决于函数的调用方式;它们的范围来自它们在脚本中出现的位置this 但是行为不同,并且可以具有不同的绑定,这取决于它在脚本中出现的位置而不是 如何。因此,对于学习该语言的人来说,它可能是一个困惑的根源,但要成为一名熟练的 JavaScript 开发人员,掌握它是必要的。

        由于this 是动态绑定的,因此有多种方法可以根据您调用函数的方式更改其值。


        示例

        当你在 JavaScript 中执行一个函数时,默认的thiswindow

        function foo() {
            console.log(this);
        }
        
        foo(); // => window
        

        this 值可以通过多种方式进行更改。一种方法是将函数作为对象的方法调用:

        var x = {
            foo: function() {
                console.log(this);
            }
        };
        x.foo(); // => This time it's the x object.
        

        另一种方法是使用callapply 告诉函数在某个对象的上下文中执行。

        function foo() {
            console.log(this);
        }
        foo.call(x); // => x object again
        foo.apply(x); // => x object as well
        

        如果你在nullundefinedcallapply,则会再次出现默认行为:该函数将在window的上下文中执行:

        function foo() {
            console.log(this);
        }
        foo.call(null); // => window
        foo.apply(undefined); // => window
        

        但是,请注意,在 ECMAScript 5 严格模式中,this 不默认为窗口:

        (function() {
        
            'use strict';
        
            function foo() {
                console.log(this);
            }
        
            foo(); // => undefined
            foo.call(null); // => null
            foo.apply(undefined); // => undefined
        
        })();
        

        您也可以设置this,在调用之前使用bind将函数绑定到对象:

        function foo() {
            console.log(this);
        }
        
        var bar = {
            baz: 'some property'
        };
        
        var foobar = foo.bind(bar);
        
        foobar(); // => calls foo with bar as this
        

        Going Father: Lazy Bind / Uncurrying this

        更进一步,您有时可能希望采用作用于this 的函数,并允许将this 值作为函数的第一个参数传入。这对于 Array 方法非常有用,例如 forEach。例如,假设您正在处理一个类似数组但实际上不是数组的对象。

        var arrayLike = {
            '0': 'a',
            '1': 'b',
            '2': 'c',
            'length': 3
        };
        

        如果你想用forEach 迭代这个对象,你可以使用call

        Array.prototype.forEach.call(arrayLike, function(item) {
            console.log(item);
        });
        // Logs: a, b, c
        

        但是,另一种选择是创建一个forEach 函数,该函数可以直接在您的对象上调用:

        var forEach = Function.prototype.call.bind(Array.prototype.forEach);
        

        现在您可以随时使用此函数来迭代类似数组的对象:

        forEach(arrayLike, function(item) {
            console.log(item);
        });
        // Logs: a, b, c
        

        有时这种方法被称为“uncurrying this”。但是,我更喜欢创建一个可以生成这些“非curried”函数并将其称为“惰性绑定”的函数。

        var lazyBind = Function.prototype.bind.bind(Function.prototype.call);
        
        var forEach = lazyBind(Array.prototype.forEach);
        var slice = lazyBind(Array.prototype.slice);
        var map = lazyBind(Array.prototype.map);
        
        forEach(arrayLike, function(u) {
            console.log(u);
        });
        // Logs: a, b, c
        
        var realArray = slice(arrayLike);
        // Converts arrayLike into a real array
        
        forEach(
            map(arrayLike, function(u) {
                return u + 'Q';
            }),
            function(u) {
                console.log(u);
            }
        );
        // Logs: aQ, bQ, cQ
        

        关于这种技术的一个非常棒的事情是它可以用于创建安全的 JavaScript,如果您不希望页面上的其他脚本窥探您的内部变量,这将很有帮助。不过,这是一种非常先进的元编程技术,您在日常的 JavaScript 中看不到它。

        【讨论】:

          猜你喜欢
          • 2013-04-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多