我有注册一个事件处理程序的构造函数:
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);
但是,我不能够访问data
的回调内创建的对象的属性。 它看起来像this
并不是指所创建的对象,但到另一个。
我还试图用一个对象的方法,而不是一个匿名函数:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', this.alert);
}
MyConstructor.prototype.alert = function() {
alert(this.name);
};
但它表现出了同样的问题。
我如何才能获得正确的对象?
Answer 1:
你应该知道什么this
this
(又名“上下文”)是每个函数里面一个特殊的关键字,它的值只取决于函数是怎么被调用,而不是如何/何时/何地它被定义。 它不受词法作用域像其他变量(除箭头功能,见下文)。 这里有些例子:
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`
要了解更多关于this
,看看在MDN文档 。
如何引用正确的this
不要使用this
你其实并不想访问this
特别, 但对象是指 。 这就是为什么一个简单的解决方案是简单地创建一个新的变量,也指该对象。 该变量可以有任何名称,但常见的是self
和that
。
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
由于self
是正常的变量,它服从词法范围的规则,是在回调中访问。 这也有可以访问的优势, this
回调本身的价值。
明确设置this
回调-第1部分
它看起来像你有过的价值无法控制this
,因为它的值是自动设置的,但实际上并非如此。
每个函数都有所述方法.bind
[文档] ,它返回一个新的功能this
绑定到一个值。 该功能具有完全相同的行为,你那叫一个.bind
上,只有this
被你设置。 不管如何或何时调用该函数, this
总是引用传递的值。
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
在这种情况下,我们绑定回调的this
以价值MyConstructor
的this
。
注意:当jQuery的绑定上下文,使用jQuery.proxy
[文件]代替。 之所以这样做,这是使取消绑定事件回调时,你并不需要参考存储功能。 jQuery的处理是在内部。
ECMAScript中6:使用箭头功能
的ECMAScript 6引入箭头的功能 ,其可以被认为是lambda函数。 他们没有自己的this
具有约束力。 相反, this
是抬头范围就像一个正常的变量。 这意味着你不必调用.bind
。 这不是他们唯一的特殊行为,请参阅MDN文档的详细信息。
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
设置this
回调-第2部分
其中接受回调的某些功能/方法也接受一个值的回调的到this
应该是指。 这基本上是一样的自己约束力,但该函数/方法会为你。 Array#map
[文档]是这样一种方法。 它的签名是:
array.map(callback[, thisArg])
第一个参数是回调,第二个参数是值this
应该参考。 这里是一个人为的例子:
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
注:无论是否可以传递一个值, this
通常是函数/方法的文档中提到。 例如, jQuery的$.ajax
法[文件]描述了一个叫选项context
:
这个对象将作出所有Ajax相关回调的背景下。
常见问题:使用对象方法的回调/事件处理程序
当一个对象的方法被用作回调/事件处理此问题的另一个常见的表现是。 函数是JavaScript中的一等公民和术语“方法”仅仅是一个函数,对象属性的值的口语期限。 但是,这个功能并没有一个特定的链接到它的“含”对象。
请看下面的例子:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
该功能this.method
被指定为click事件处理,但如果document.body
点击,记录值将undefined
,因为在事件处理中, this
指的是document.body
,没有实例Foo
。
正如开头已经提到的,什么this
是指依赖于该函数的调用 ,它不是如何定义的 。
如果代码就像下面,可能会更明显,功能没有对象的隐式引用:
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
解决的办法是与上述相同提到:如果可用,使用.bind
显式绑定this
在某一特定值
document.body.onclick = this.method.bind(this);
或显式调用函数作为对象的“方法”,通过使用匿名函数作为回调/事件处理程序和对象(分配this
)到另一个变量:
var self = this;
document.body.onclick = function() {
self.method();
};
或使用箭头功能:
document.body.onclick = () => this.method();
Answer 2:
这里有几种方式可访问子上下文中父上下文 -
- 您可以使用
bind ()
函数。 - 存储参考上下文/这个另一变量中(见下例)。
- 使用ES6 箭头功能。
- 改变代码/功能设计/建筑-这个你应该有指挥权的设计模式在JavaScript。
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);
如果您正在使用underscore.js
- http://underscorejs.org/#bind
transport.on('data', _.bind(function () {
alert(this.data);
}, this));
2存储参照上下文/这个另一个变量内
function MyConstructor(data, transport) {
var self = this;
this.data = data;
transport.on('data', function() {
alert(self.data);
});
}
3 Arrow功能
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
Answer 3:
这一切都在调用一个方法的“神奇”的语法:
object.property();
当你从对象获得的财产,并把它一气呵成,对象将是该方法的上下文。 如果你调用相同的方法,但在单独的步骤中,上下文是全球范围内(窗口),而不是:
var f = object.property;
f();
当你得到一个方法的参考,它不再附着在物体上,它只是一个纯函数的引用。 当你作为一个回调使用参考同样的情况:
this.saveNextLevelData(this.setAll);
这就是你会结合上下文的功能:
this.saveNextLevelData(this.setAll.bind(this));
如果你正在使用jQuery的你应该使用$.proxy
方法来代替,如bind
是不是在所有的浏览器都支持:
this.saveNextLevelData($.proxy(this.setAll, this));
Answer 4:
有“背景”的麻烦
术语“上下文”有时用来指通过此引用的对象。 它的使用是不合适的,因为它不适合任何语义或技术上与ECMAScript中的这个 。
“背景”是指周围的东西更有意义,或者一些之前和之后的信息提供额外含义的情形。 术语“上下文” ECMAScript中用于指代执行上下文 ,这是所有的参数,范围和这个的一些执行的代码的范围内。
这示出在ECMA-262部分10.4.2 :
设置ThisBinding为相同的值与调用执行上下文的ThisBinding
这清楚地表明这是一个执行上下文的一部分。
一个执行上下文提供周边信息,增加了含义正在执行的代码。 它包括的不仅仅是更多的信息thisBinding 。
所以这个值是不是“背景”,它只是一个执行上下文的一部分。 它本质上是可以被调用的任何对象,并在严格模式下都可以设置,为任意值的局部变量。
Answer 5:
首先,你需要有一个清醒的认识scope
和行为, this
关键字的上下文scope
。
this
与scope
:
there are two types of scope in javascript. They are :
1) Global Scope
2) Function Scope
总之,全球范围内是指在全球范围内声明的窗口object.Variables从anywhere.On访问另一方面函数范围驻留在函数内声明的function.variable内不能从外界的正常访问。 this
关键字在全球范围内指的是window对象。 this
里面函数也指窗口object.So 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 -
--------------------------------------------------------------------------------
不同的方式来处理this
里面回调函数:
在这里,我有一个名为的人一个构造函数。 它有一个属性称为name
和四个方法称为sayNameVersion1
, sayNameVersion2
, sayNameVersion3
, sayNameVersion4
。 他们四个有一个特定task.Accept的回调和调用后援回调有一个特定的任务是记录人的构造函数的一个实例的name属性。
function Person(name){
this.name = name
this.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 callback
var parentObject = this
console.log(parentObject)
}
现在,让我们创建一个从人的构造函数的实例并调用的不同版本sayNameVersionX
(X指的是1,2,3,4)法niceCallback
,看看我们有多少种方法可以操纵this
里面回调指person
实例。
var p1 = new Person('zami') // create an instance of Person constructor
绑定:
什么绑定要做的就是创建一个新的功能与this
关键字设置为所提供的价值。
sayNameVersion1
和sayNameVersion2
使用绑定来操纵this
回调函数。
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
第一个结合this
与方法itself.And内部回调第二个回调被传递与结合于它的对象。
p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method
p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback
拨打:
的first argument
的的call
方法被用作this
被调用与函数内call
连接到它。
sayNameVersion3
使用call
来操作this
指的不是window对象,我们创建的Person对象。
this.sayNameVersion3 = function(callback){
callback.call(this)
}
它被称为像下面这样:
p1.sayNameVersion3(niceCallback)
适用于:
类似call
的第一个参数apply
是指将被指示的对象this
关键字。
sayNameVersion4
使用apply
来操纵this
指Person对象
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
它被称为像following.Simply回调传递,
p1.sayNameVersion4(niceCallback)
Answer 6:
你应该知道“this”关键字。
按我的观点,你可以实现“本”在三个方面 (自我/ Arrow功能/绑定方法)
相对于其他语言在JavaScript函数的此关键字的行为方式有所不同。
它也有严格的之间的模式和非严格模式的一些差别。
在大多数情况下,这个值是通过一个函数是如何被调用来确定。
它不能被分配在执行期间设置,并且每一个函数被调用时它可以是不同的。
ES5引入了bind()方法来设置功能的价值这个不管它怎么叫,
和ES2015引入箭头功能不提供它们自己的这种结合(它保留了包围词汇上下文的此值)。
方法一:自我-自我是被用来保持甚至上下文原来的这个基准发生变化。 它通常在事件处理程序使用(尤其是在闭包)的技术。
参考 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function () {
alert(self.data);
});
}
方法2:箭头功能-的箭头函数表达式是语法上紧凑的替代正规的函数表达式,
虽然没有自己的绑定到这一点,参数,超,或new.target关键字。
箭函数表达式是不适合的方法,并且它们不能被用作构造函数。
参考 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',()=> {
alert(this.data);
});
}
方法3:Bind-的bind()方法创建一个新的功能,
调用时,有该关键字设置为所提供的价值,
与前述的当新功能被调用任何设置参数给定的序列。
参考: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',(function() {
alert(this.data);
}).bind(this);
Answer 7:
我们不能绑定这setTimeout()
如果你想访问,因为它总是与全局对象(窗口)执行, this
然后通过使用回调函数的上下文bind()
回调函数我们可以实现如下:
setTimeout(function(){
this.methodName();
}.bind(this), 2000);
Answer 8:
现在的问题是围绕如何this
关键字在JavaScript行为。 this
下面的行为不同,
- 的值
this
通常是通过一个功能的执行上下文来确定。 - 在全球范围内,
this
指的是全局对象(该window
对象)。 - 如果严格模式是所有功能则值启用
this
将undefined
为在严格模式下,全局对象指的是undefined
替代的window
对象。 - 即点之前站在目的是什么,这个关键字将被绑定到。
- 我们可以明确地设置这个值
call()
, bind()
并apply()
- 当
new
使用的关键字(一个构造函数),这势必要创建的新对象。 - 箭功能不与
this
-相反, this
是(基于原始上下文IE)词法约束
由于大部分的答案表明,我们可以使用Arrow功能或bind()
方法或自我变种。 我想举一个有关的lambda点(Arrow功能)从谷歌的JavaScript风格指南
喜欢使用超过f.bind(本)箭头功能,并且尤其是在goog.bind(F,这一点)。 避免写常量自我=这一点。 箭头功能是回调,这有时会意外传递额外的参数是特别有用的。
谷歌显然推荐使用lambda表达式,而不是绑定或const self = this
所以最好的解决办法是使用lambda表达式如下,
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
参考文献:
- https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
- 箭头功能-VS绑定
Answer 9:
目前还有另一种方法可能的,如果类是在代码中使用。
随着支持的类字段它可能使下一个方法:
class someView {
onSomeInputKeyUp = (event) => {
console.log(this); // this refers to correct value
// ....
someInitMethod() {
//...
someInput.addEventListener('input', this.onSomeInputKeyUp)
对于引擎盖下确保它是结合上下文的所有老好箭头的功能,但以这种形式看起来更清楚,明确的约束力。
由于这是第3阶段的提案则需要巴贝尔和适当的巴别塔的插件来处理它为现在(08/2018)。
Answer 10:
另一种方法,这是因为DOM2标准的方式绑定this
事件侦听器内, 使您可以随时删除监听器 (还有其他好处),是handleEvent(evt)
从法EventListener
接口:
var obj = {
handleEvent(e) {
// always true
console.log(this === obj);
}
};
document.body.addEventListener('click', obj);
有关使用的详细信息handleEvent
可以在这里找到: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38
文章来源: How to access the correct `this` inside a callback?