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

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

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

从以下内容: 在回调函数中访问$(this)

我想知道是否有人可以扩展这里到底发生了什么(为什么没有重新分配就无法获得?)以及我应该阅读哪些核心信息? 从我收集的内容来看,这可能与封闭有关……这是我在搜索时碰到的大部分内容。 这是准确的吗?

在我的情况下,我想要执行一些代码,然后在ajax请求完成后重定向。 在回调函数中,我运行$(this).attr("href") ,返回undefined。

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

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

仅供参考,其中一些方式是:

  • obj.method()this method()将被设置为obj
  • func.call(obj)thisfunc()中将设置为obj
  • func()this将在func()设置为window ,或在严格模式下设置为undefined

这意味着根据您所处的位置而变化。 在click事件的处理程序中, 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); } } 

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

 $("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是依赖于上下文的,你经常需要保留它在一个上下文中的值,并在另一个上下文中使用它。

来自ECMAScript规范的引用:

10.1.7这个

每个活动执行上下文都有一个值。 值取决于调用者和正在执行的代码类型,并在控制进入执行上下文时确定。

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

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

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

简要概述

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

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


例子

在JavaScript中执行函数时,默认为window

 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 

如果callapply nullundefined ,则会再次出现默认行为:该函数将在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 })(); 

您也可以通过使用bind在调用之前将函数bind到对象来设置它:

 function foo() { console.log(this); } var bar = { baz: 'some property' }; var foobar = foo.bind(bar); foobar(); // => calls foo with bar as 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 

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

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