在回调函数中访问变量......什么?

时间:2012-12-02 03:03:18

标签: javascript jquery

我经历了大量的帖子,我终于得到了我需要的东西,这要归功于:

$("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"),返回undefined。

4 个答案:

答案 0 :(得分:3)

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

因此,除非jPrompt通过您传入的某个参数来保持this的相同值,否则它可能会有不同的值。因此,您可以将其保存,以便在回调中进行访问。这是javacscript回调中非常常见的设计模式。

仅供参考,obj.method()分配的一些方式:

  • this - method()中的obj将设置为func.call(obj)
  • this - func()中的obj将设置为func()
  • this - window将在func()undefined中以严格模式设置为{{1}}

答案 1 :(得分:1)

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

$("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这个

     

值与之关联   每个活动执行上下文。该   值取决于调用者和   正在执行的代码类型   当控制进入时确定   执行上下文。

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

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

这些人提供了详细而且通常非常准确的优秀文档(与谷歌搜索中经常出现的其他热门参考资料不同 - w3cshools.com我在想你!)。

答案 2 :(得分:1)

this的含义会根据您所处的位置而变化。点击事件处理程序中的this表示传递给this函数的回调中jPrompt以外的其他内容。

对于它的价值,您不需要重新分配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 :(得分:1)

this

的简短概述 JavaScript中的

this 动态范围。它的行为与词法范围的所有其他变量不同。其他变量没有不同的绑定,具体取决于调用函数的 ;它们的范围来自,其中它们出现在脚本中。 this但行为有所不同,并且可以有不同的绑定,这取决于它出现在脚本中的 where ,而不是 它的调用方式。因此,它可能成为人们学习语言的混乱源,但掌握它对于成为一名熟练的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

如果您callapplynullundefined,则会再次出现默认行为:该函数将在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值作为函数的第一个参数传入。这对于数组方法非常有用,例如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”。但是,我更喜欢创建一个可以生成这些“uncurried”函数的函数,并将其称为“lazy binding”。

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中看到它。