本文翻译自:How to access the correct `this` inside a callback?

I have a constructor function which registers an event handler: 我有一个构造函数注册一个事件处理程序:

 function MyConstructor(data, transport) { this.data = data; transport.on('data', function () { alert(this.data); }); } // Mock transport object var transport = { on: function(event, callback) { setTimeout(callback, 1000); } }; // called as var obj = new MyConstructor('foo', transport); 

However, I'm not able to access the data property of the created object inside the callback. 但是,我无法在回调内部访问已创建对象的data属性。 It looks like this does not refer to the object that was created but to an other one. 看起来this并不引用创建的对象,而是引用另一个对象。

I also tried to use an object method instead of an anonymous function: 我还尝试使用对象方法而不是匿名函数:

function MyConstructor(data, transport) {this.data = data;transport.on('data', this.alert);
}MyConstructor.prototype.alert = function() {alert(this.name);
};

but it exhibits the same problems. 但是也有同样的问题

How can I access the correct object? 如何访问正确的对象?


#1楼

参考:https://stackoom.com/question/1N5cS/如何在回调中访问正确的-this


#2楼

What you should know about this 你应该知道什么this

this (aka "the context") is a special keyword inside each function and its value only depends on how the function was called, not how/when/where it was defined. this (又名“上下文”)是每个函数里面一个特殊的关键字,它的值只取决于函数是怎么被调用,而不是如何/何时/何地它被定义。 It is not affected by lexical scopes like other variables (except for arrow functions, see below). 它不受其他变量之类的词法作用域的影响(箭头函数除外,请参见下文)。 Here are some examples: 这里有些例子:

function foo() {console.log(this);
}// normal function call
foo(); // `this` will refer to `window`// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

To learn more about this , have a look at the MDN documentation . 要了解更多关于this ,看看在MDN文档 。


How to refer to the correct this 如何引用正确的this

Don't use this 不要用this

You actually don't want to access this in particular, but the object it refers to . 实际上,您实际上不想访问this 对象 ,但是要访问它所指向的对象 That's why an easy solution is to simply create a new variable that also refers to that object. 这就是为什么一个简单的解决方案是简单地创建一个也引用该对象的新变量。 The variable can have any name, but common ones are self and that . 该变量可以具有任何名称,但是常见的名称是selfthat

function MyConstructor(data, transport) {this.data = data;var self = this;transport.on('data', function() {alert(self.data);});
}

Since self is a normal variable, it obeys lexical scope rules and is accessible inside the callback. 由于self是一个普通变量,因此它遵循词汇范围规则,并且可以在回调内部进行访问。 This also has the advantage that you can access the this value of the callback itself. 这还有一个优点,就是您可以访问回调本身的this值。

Explicitly set this of the callback - part 1 明确设置this回调-第1部分

It might look like you have no control over the value of this because its value is set automatically, but that is actually not the case. 它看起来像你有过的价值无法控制this ,因为它的值是自动设置的,但实际上并非如此。

Every function has the method .bind [docs] , which returns a new function with this bound to a value. 每个函数都有所述方法.bind [文档] ,它返回一个新的功能this绑定到一个值。 The function has exactly the same behaviour as the one you called .bind on, only that this was set by you. 该功能具有完全相同的行为,你那叫一个.bind上,只有this被你设置。 No matter how or when that function is called, this will always refer to the passed value. 无论如何或何时调用该函数, this始终引用传递的值。

function MyConstructor(data, transport) {this.data = data;var boundFunction = (function() { // parenthesis are not necessaryalert(this.data);             // but might improve readability}).bind(this); // <- here we are calling `.bind()` transport.on('data', boundFunction);
}

In this case, we are binding the callback's this to the value of MyConstructor 's this . 在这种情况下,我们绑定回调就是this以价值MyConstructorthis

Note: When binding context for jQuery, use jQuery.proxy [docs] instead. 注意:当为jQuery绑定上下文时,请改用jQuery.proxy [docs] The reason to do this is so that you don't need to store the reference to the function when unbinding an event callback. 这样做的原因是,使您在取消绑定事件回调时不需要存储对该函数的引用。 jQuery handles that internally. jQuery在内部进行处理。

ECMAScript 6: Use arrow functions ECMAScript 6:使用箭头功能

ECMAScript 6 introduces arrow functions , which can be thought of as lambda functions. ECMAScript 6引入了箭头功能 ,可以将其视为lambda函数。 They don't have their own this binding. 自己他们没有this约束力。 Instead, this is looked up in scope just like a normal variable. 相反, this像普通变量一样在作用域中查找。 That means you don't have to call .bind . 这意味着您不必调用.bind That's not the only special behaviour they have, please refer to the MDN documentation for more information. 这不是它们唯一的特殊行为,请参考MDN文档以获取更多信息。

function MyConstructor(data, transport) {this.data = data;transport.on('data', () => alert(this.data));
}

Set this of the callback - part 2 设置this回调-第2部分

Some functions/methods which accept callbacks also accept a value to which the callback's this should refer to. 其中接受回调的某些功能/方法也接受一个值,其回调是this应该是指。 This is basically the same as binding it yourself, but the function/method does it for you. 这基本上与您自己绑定它相同,但是函数/方法可以为您完成它。 Array#map [docs] is such a method. Array#map [docs]是这种方法。 Its signature is: 它的签名是:

array.map(callback[, thisArg])

The first argument is the callback and the second argument is the value this should refer to. 第一个参数是回调,第二个参数是值this应该参考。 Here is a contrived example: 这是一个人为的示例:

var arr = [1, 2, 3];
var obj = {multiplier: 42};var new_arr = arr.map(function(v) {return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

Note: Whether or not you can pass a value for this is usually mentioned in the documentation of that function/method. 注意:该函数/方法的文档中通常会提到是否可以this传递值。 For example, jQuery's $.ajax method [docs] describes an option called context : 例如, jQuery的$.ajax方法[docs]描述了一个称为context的选项:

This object will be made the context of all Ajax-related callbacks. 该对象将成为所有与Ajax相关的回调的上下文。


Common problem: Using object methods as callbacks/event handlers 常见问题:使用对象方法作为回调/事件处理程序

Another common manifestation of this problem is when an object method is used as callback/event handler. 此问题的另一个常见表现是将对象方法用作回调/事件处理程序。 Functions are first-class citizens in JavaScript and the term "method" is just a colloquial term for a function that is a value of an object property. 函数是JavaScript中的一等公民,术语“方法”仅是一个俗称的函数,即对象属性的值。 But that function doesn't have a specific link to its "containing" object. 但是该函数没有指向其“包含”对象的特定链接。

Consider the following example: 考虑以下示例:

function Foo() {this.data = 42,document.body.onclick = this.method;
}Foo.prototype.method = function() {console.log(this.data);
};

The function this.method is assigned as click event handler, but if the document.body is clicked, the value logged will be undefined , because inside the event handler, this refers to the document.body , not the instance of Foo . 函数this.method被分配为click事件处理程序,但是如果单击document.body ,则记录的值将是undefined ,因为在事件处理程序内部, this引用document.body ,而不是Foo的实例。
As already mentioned at the beginning, what this refers to depends on how the function is called , not how it is defined . 正如开头已经提到的,什么this是指依赖于该函数的调用 ,它不是如何定义的
If the code was like the following, it might be more obvious that the function doesn't have an implicit reference to the object: 如果代码如下所示,则该函数没有对该对象的隐式引用可能会更加明显:

function method() {console.log(this.data);
}function Foo() {this.data = 42,document.body.onclick = this.method;
}Foo.prototype.method = method;

The solution is the same as mentioned above: If available, use .bind to explicitly bind this to a specific value 如果可能,使用:如上面提到的解决方案是相同.bind将其明确绑定this在某一特定值

document.body.onclick = this.method.bind(this);

or explicitly call the function as a "method" of the object, by using an anonymous function as callback / event handler and assign the object ( this ) to another variable: 或通过将匿名函数用作回调/事件处理程序并将对象( this )分配给另一个变量,来显式调用该函数作为对象的“方法”:

var self = this;
document.body.onclick = function() {self.method();
};

or use an arrow function: 或使用箭头功能:

document.body.onclick = () => this.method();

#3楼

It's all in the "magic" syntax of calling a method: 所有这些都是调用方法的“魔术”语法:

object.property();

When you get the property from the object and call it in one go, the object will be the context for the method. 当您从对象获得属性并一次性调用它时,该对象将成为方法的上下文。 If you call the same method, but in separate steps, the context is the global scope (window) instead: 如果您调用相同的方法,但在单独的步骤中,则上下文将改为全局作用域(窗口):

var f = object.property;
f();

When you get the reference of a method, it's no longer attached to the object, it's just a reference to a plain function. 当您获得方法的引用时,它不再附加到对象上,而只是对普通函数的引用。 The same happens when you get the reference to use as a callback: 当您将引用用作回调时,也会发生相同的情况:

this.saveNextLevelData(this.setAll);

That's where you would bind the context to the function: 那是将上下文绑定到函数的地方:

this.saveNextLevelData(this.setAll.bind(this));

If you are using jQuery you should use the $.proxy method instead, as bind is not supported in all browsers: 如果您使用的是jQuery,则应改用$.proxy方法,因为并非所有浏览器都支持bind

this.saveNextLevelData($.proxy(this.setAll, this));

#4楼

The trouble with "context" 麻烦与“上下文”

The term "context" is sometimes used to refer to the object referenced by this . 术语“上下文”有时用于表示this引用的对象。 Its use is inappropriate because it doesn't fit either semantically or technically with ECMAScript's this . 它的使用是不合适的,因为它在语义上或技术上都不适合ECMAScript的this

"Context" means the circumstances surrounding something that adds meaning, or some preceding and following information that gives extra meaning. “上下文”是指围绕某些事物增加含义的环境,或一些提供额外含义的前后信息。 The term "context" is used in ECMAScript to refer to execution context , which is all the parameters, scope and this within the scope of some executing code. 术语“上下文” ECMAScript中用于指代执行上下文 ,这是所有的参数,范围和这个的一些执行的代码的范围内。

This is shown in ECMA-262 section 10.4.2 : 这在ECMA-262第10.4.2节中显示 :

Set the ThisBinding to the same value as the ThisBinding of the calling execution context 将ThisBinding设置为与调用执行上下文的ThisBinding相同的值

which clearly indicates that this is part of an execution context. 这清楚地表明是执行上下文的一部分。

An execution context provides the surrounding information that adds meaning to code that is being executed. 执行上下文提供了周围的信息,这些信息为正在执行的代码增加了含义。 It includes much more information than just the thisBinding . 它不仅包含thisBinding ,还包含更多信息。

So the value of this isn't "context", it's just one part of an execution context. 因此, 值不是“上下文”,而只是执行上下文的一部分。 It's essentially a local variable that can be set by the call to any object and in strict mode, to any value at all. 它本质上是一个局部变量,可以通过对任何对象的调用以及在严格模式下将其设置为所有值。


#5楼

Here are several ways to access parent context inside child context - 以下是在子上下文中访问父上下文的几种方法-

  1. You can use bind () function. 您可以使用bind ()函数。
  2. Store reference to context/this inside another variable(see below example). 将对上下文/ this的引用存储在另一个变量中(请参见下面的示例)。
  3. Use ES6 Arrow functions. 使用ES6 箭头功能。
  4. Alter code/function design/architecture - for this you should have command over design patterns in javascript. 更改代码/功能设计/架构-为此,您应该对javascript中的设计模式有命令。

1. Use bind() function 1.使用bind()函数

function MyConstructor(data, transport) {this.data = data;transport.on('data', ( function () {alert(this.data);}).bind(this) );
}
// Mock transport object
var transport = {on: function(event, callback) {setTimeout(callback, 1000);}
};
// called as
var obj = new MyConstructor('foo', transport);

If you are using underscore.js - http://underscorejs.org/#bind 如果您使用的是underscore.js - http://underscorejs.org/#bind

transport.on('data', _.bind(function () {alert(this.data);
}, this));

2 Store reference to context/this inside another variable 2将对上下文/ this的引用存储在另一个变量中

function MyConstructor(data, transport) {var self = this;this.data = data;transport.on('data', function() {alert(self.data);});
}

3 Arrow function 3箭头功能

function MyConstructor(data, transport) {this.data = data;transport.on('data', () => {alert(this.data);});
}

#6楼

First, you need to have a clear understanding of scope and behaviour of this keyword in the context of scope . 首先,您需要对scopethis关键字在scope上下文中的行为有清楚的了解。

this & scope : thisscope


there are two types of scope in javascript. They are :1) Global Scope2) Function Scope

in short, global scope refers to the window object.Variables declared in a global scope are accessible from anywhere.On the other hand function scope resides inside of a function.variable declared inside a function cannot be accessed from outside world normally. 简而言之,全局作用域是指window对象。在全局作用域中声明的变量可以从任何地方访问;另一方面,函数作用域位于函数内部。在函数内部声明的变量通常不能从外部访问。 this keyword in global scope refers to the window object. 全局范围内的this关键字引用窗口对象。 this inside function also refers to the window object.So this will always refer to the window until we find a way to manipulate this to indicate a context of our own choosing. this内部函数也指的是窗口对象, this它将一直指代窗口,直到我们找到一种方法来操纵this以表明我们自己选择的上下文为止。

--------------------------------------------------------------------------------
-                                                                              -
-   Global Scope                                                               -
-   ( globally "this" refers to window object)                                 -
-                                                                              -
-         function outer_function(callback){                                   -
-                                                                              -
-               // outer function scope                                        -
-               // inside outer function"this" keyword refers to window object -                                                                              -
-              callback() // "this" inside callback also refers window object  --         }                                                                    -
-                                                                              -
-         function callback_function(){                                        -
-                                                                              -
-                //  function to be passed as callback                         -
-                                                                              -
-                // here "THIS" refers to window object also                   -
-                                                                              -
-         }                                                                    -
-                                                                              -
-         outer_function(callback_function)                                    -
-         // invoke with callback                                              -
--------------------------------------------------------------------------------

Different ways to manipulate this inside callback functions: 在回调函数内部处理this不同方法:

Here I have a constructor function called Person. 在这里,我有一个名为Person的构造函数。 It has a property called name and four method called sayNameVersion1 , sayNameVersion2 , sayNameVersion3 , sayNameVersion4 . 它具有一个名为name的属性和四个名为sayNameVersion1sayNameVersion2sayNameVersion3sayNameVersion4All four of them has one specific task.Accept a callback and invoke it.The callback has a specific task which is to log the name property of an instance of Person constructor function. 它们全部有一个特定的任务。接受一个回调并调用它。回调具有一个特定的任务,即记录Person构造函数实例的name属性。

function Person(name){this.name = namethis.sayNameVersion1 = function(callback){callback.bind(this)()}this.sayNameVersion2 = function(callback){callback()}this.sayNameVersion3 = function(callback){callback.call(this)}this.sayNameVersion4 = function(callback){callback.apply(this)}}function niceCallback(){// function to be used as callbackvar parentObject = thisconsole.log(parentObject)}

Now let's create an instance from person constructor and invoke different versions of sayNameVersionX ( X refers to 1,2,3,4 ) method with niceCallback to see how many ways we can manipulate the this inside callback to refer to the person instance. 现在,让我们创建一个从人的构造函数和调用不同版本的实例sayNameVersionX (X指的是1,2,3,4)法niceCallback ,看看我们有多少种方法可以操纵this里面回调指person实例。

var p1 = new Person('zami') // create an instance of Person constructor

bind : 绑定:

What bind do is to create a new function with the this keyword set to the provided value. 绑定的作用是使用this关键字设置为提供的值来创建一个新函数。

sayNameVersion1 and sayNameVersion2 use bind to manipulate this of the callback function. sayNameVersion1sayNameVersion2使用绑定来操纵this回调函数。

this.sayNameVersion1 = function(callback){callback.bind(this)()
}
this.sayNameVersion2 = function(callback){callback()
}

first one bind this with callback inside the method itself.And for the second one callback is passed with the object bound to it. 第一个结合this与方法itself.And为第二个回调内部回调被传递与结合于它的对象。

p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 methodp1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback

call : 致电:

The first argument of the call method is used as this inside the function that is invoked with call attached to it. first argument的的call方法被用作this内部时调用与函数call连接到它。

sayNameVersion3 uses call to manipulate the this to refer to the person object that we created, instead of the window object. sayNameVersion3使用call操作this来引用我们创建的人员对象,而不是窗口对象。

this.sayNameVersion3 = function(callback){callback.call(this)
}

and it is called like the following : 它的名称如下:

p1.sayNameVersion3(niceCallback)

apply : 适用:

Similar to call , first argument of apply refers to the object that will be indicated by this keyword. call相似, apply第一个参数指的是将this关键字指示的对象。

sayNameVersion4 uses apply to manipulate this to refer to person object sayNameVersion4用途apply于操纵this指Person对象

this.sayNameVersion4 = function(callback){callback.apply(this)
}

and it is called like the following.Simply the callback is passed, 它的调用方式如下所示:只需传递回调,

p1.sayNameVersion4(niceCallback)

如何在回调中访问正确的“ this”?相关推荐

  1. Day 27: Restify —— 在Node.js中构建正确的REST Web服务

    今天决定学一个叫做restify的Node.js模块.restify模块使得在Node.js中写正确的REST API变得容易了很多,而且它还提供了即装即用的支持,如版本控制.错误处理.CORS和内容 ...

  2. JavaScript中错误正确处理方式,你用对了吗? 1

    JavaScript的事件驱动范式增添了丰富的语言,也是让使用JavaScript编程变得更加多样化.如果将浏览器设想为JavaScript的事件驱动工具,那么当错误发生时,某个事件就会被抛出.理论上 ...

  3. react回调函数_React中的回调中自动绑定ES6类函数

    在使用ES6类的React组件时,您必须遇到这种现象,必须显式绑定类函数,然后将其传递给诸如onClick.例如,采用以下示例. import React from 'react';class MyC ...

  4. 改善C#程序的建议3:在C#中选择正确的集合进行编码

    原文:改善C#程序的建议3:在C#中选择正确的集合进行编码 要选择正确的集合,我们首先要了解一些数据结构的知识.所谓数据结构,就是相互之间存在一种或多种特定关系的数据元素的集合.结合下图,我们看一下对 ...

  5. java下列语句正确的是_下列Java语句中,不正确的一项是( )。

    [多选题]装卸搬运机械具有( )功能 [判断题]char[] str="abcdefgh"; ( ) [单选题]7.关于内部类,下列说法不正确的是( ). [单选题]下列关于Jav ...

  6. 【Groovy】编译时元编程 ( ASTTransformation#visit 方法中访问 Groovy 类、方法、字段、属性 | 完整代码示例及进行编译时处理的编译过程 )

    文章目录 一.ASTTransformation#visit 方法中访问 Groovy 类.方法.字段.属性 二.完整代码示例及进行编译时处理的编译过程 1.Groovy 脚本 Groovy.groo ...

  7. php访问数组用引号_php双引号中访问数组元素报错如何解决

    最近在做微信公众号开发,在一个发送图文接口中,需要把数组元素拼接在XML字符串中,本文主要和大家分享一篇基于php双引号中访问数组元素报错的解决方法,具有很好的参考价值,希望对大家有所帮助.一起跟随小 ...

  8. 在ASP.NET AJAX 1.0框架中访问Web服务

    一. 简介     如今,微软最新推出的AJAX框架为ASP.NET AJAX 1.0(下载地址为[url]http://ajax.asp.net/downloads/default.aspx[/ur ...

  9. JavaScript中错误正确处理方式,你用对了吗?

    JavaScript的事件驱动范式增添了丰富的语言,也是让使用JavaScript编程变得更加多样化.如果将浏览器设想为JavaScript的事件驱动工具,那么当错误发生时,某个事件就会被抛出.理论上 ...

最新文章

  1. ubuntu 14.04 安装oracle 11g,ubuntu 14.04 安装 oracle 11g
  2. centos php 安装mysql_CentOS上安装Mysql+PHP-fpm+Nginx
  3. neo4j 迁移_在Kubernetes中迁移Neo4j图模式
  4. core 中使用 swagger
  5. 【Noip模拟 20161005】公约数
  6. android 7 apk 安装程序,Android安装apk文件并适配Android 7.0详解
  7. mac 版 SourceTree(git 客户端)跳过登录验证
  8. c语言 屏幕亮度调节_4096级屏幕亮度调节:改善安卓机自动亮度调节顽疾
  9. 两万字的CAPL语法基础,一篇文章带你入门
  10. 雷达原理---时频分析--1.基本概念
  11. 优优聚:美团,又要抢抖音的短视频生意
  12. 极兔快递 | 快递单号查询API
  13. (跨模态)AI作画——使用stable-diffusion生成图片
  14. Java写后门,JAVA简单编写后门程序
  15. SpringBoot 的请求参数校验注解
  16. [瞎搞]Lucas定理证明
  17. 找出给定字符串中大写字符(即'A'-'Z')的个数
  18. python 数学期望_python机器学习笔记:EM算法
  19. 网易游戏offer经历
  20. 什么可以有助睡眠质量?五年睡不好的我现在用这几个东西

热门文章

  1. 从os.cpus()来分析nodejs源码结构
  2. 浅析Windows计算机中丢失SETUPAPI.dll的问题
  3. brasb 密码自动应答
  4. mpvue 小程序 页面unLoad后数据没清空
  5. 《Windows Mobile平台应用与开发》写作工作顺利进行中
  6. 神奇的 37% 的概率
  7. TCP/IP详解 笔记十一
  8. ExtJS 5.1 TabReorderer plugin
  9. HP380 G9服务器RAID划分
  10. 运维工程师之-MySQL的故障问题总结