回答

收藏

如何在回调中访问正确的“this”

技术问答 技术问答 293 人阅读 | 0 人回复 | 2023-09-12

我有注册事件处理程序的构造函数:! `* g2 o) `1 k- ?3 I7 U3 d
    function MyConstructor(data,transport)    this.data = data;    transport.on('data',function ()        alert(this.data);   }Mock transport objectvar transport =    on: function(event,callback)        setTimeout(callback,   }called asvar obj = new MyConstructor('foo',transport);
    ; j0 z- h8 U0 {4 S/ J! X+ d  ]
Run code snippet
' F9 J3 K- d2 J: o- J! MExpand snippet
& a9 u0 q. ]/ S. K; ~& u但是,我无法访问data回调中创建的对象的属性。this它不是指创建的对象,而是指另一个对象。
9 M9 N7 c% @- A5 I我还试图使用对象而不是匿名函数:
8 r% S: I2 S0 |7 _
    function MyConstructor(data,transport)    this.data = data;    transport.on('data',this.alert);}MyConstructor.prototype.alert = function()    alert(this.name);};3 u/ k' O$ B# V8 q7 X+ {
但它也表现出同样的问题。+ ]: r! ^& o7 M: U2 d5 O+ M
如何访问正确的对象?
# j  `6 Y, t4 I* ]: e3 |                                                                # ]& H) z. h% f
    解决方案:                                                               
8 }% y: C5 h. |1 s                                                                ,你应该知道的thisthis(又称上下文)是每个功能中的特殊关键字,其值仅取决于如何调用函数,而不是如何/何时/何时被定义。它不像其他变量那样受词法作用域的影响(箭头函数除外,见下文)。这里有一些例子:. }1 O1 J* S2 N; N! z5 W. z! h
    function foo()      console.log(this);}// normal function callfoo(); // `this` will refer to `window`// as object methodvar obj = {bar: foo};obj.bar(); // `this` will refer to `obj`// as constructor functionnew foo(); // `this` will refer to an object that inherits from `foo.prototype`, C1 V- N  |4 f  R0 `/ d! b6 P
了解更多信息this,请查看MDN 文档。+ a* p2 g" O2 q# g: d1 B$ K/ J
如何正确引用 this使用箭头函数ECMAScript 6 引入了箭头函数,可视为 lambda 函数。他们没有自己的this绑定。this在范围内搜索就像普通变量一样。这意味着你不必调用它.bind. 这不是他们唯一的特殊行为。请参考 MDN 文档获取更多信息。
: ^! g) G4 r+ x1 Z0 C: C1 K
    function MyConstructor(data,transport)    this.data = data;    transport.on('data',() => alert(this.data));}
    5 h2 A5 g5 F& f1 n! Z
不要使用 this你实际上不想this特别访问,而是它所指的对象。这就是为什么一个简单的解决方案只是创建一个引用对象的新变量。变量可以有任何名称,但常见的是self和that。
- M: z1 x. Y/ h" R
    2 q7 ]( }" h, W+ b  H* z5 `
  • function MyConstructor(data,transport)    this.data = data;    var self = this;    transport.on('data',function()        alert(self.data);}code]由于self它是一个普通的变量,遵守词法作用域规则,可以在回调中访问。这还有另一个好处,你可以访问它this回调本身的价值。& Z! F8 M1 I0 d- f" I0 [- \4 E
  • 显式设置this回调 - 第一 部分你似乎无法控制 值,this因为它的值是自动设置的,但事实并非如此。# ^/ Y4 q0 W4 M7 q' [
  • 每个函数都有方法[.bind *docs]*,它返回一个this绑定到一个值的新函数。该函数与您调用的函数完全相同.bind,只是this由您设置。无论何时调用此函数,this将始终引用传输值。
    5 H- ~# Y& k  Q# q, g, \; r
  • [code]function MyConstructor(data,transport)    this.data = data;    var boundFunction = (function() { / parenthesis are not necessary        alert(this.data);       but might improve readability    .bind(this); // 在这种情况下,我们绑定了回调this到MyConstructor‘s的值this。. E2 w1 D- a# S+ U, l4 ]. R
  • 注意:当是 jQuery 绑定上下文时,请改用[jQuery.proxy *docs]*。这样做的原因是,在取消绑定事件回调时,您不需要存储引用函数。jQuery 内部处理。0 W' U0 N7 k& k6 @- }
  • 设置this回调-第2部分一些接受回调的函数/方法也接受回调this应引用的值。这与您自己的绑定基本相同,但函数/方法将为您完成。[Array#map *docs]*这是一种方法。它的签名是:[code]array.map(callback[,thisArg])+ Y& X, I" {9 J/ ]! w" `' w
第一个参数是回调,第二个参数是回调this值应引用。这是一个人为的例子:
' I+ S# N# E; y/ R! j' ~3 i+ l

    0 B) G) Z5 v9 B: q* b
  • var arr = [1,2,3];var obj = {multiplier: 42};var new_arr = arr.map(function(v)    return v * this.multiplier;},obj); // 注意:this函数/方法的文档通常提到您是否可以传递值。[jQuery 的$.ajax方法*docs]*描述了一个叫 的选项context:: z* D( q( L- I
  • 对象将成为所有和 Ajax 相关回调的上下文。
    3 s  P/ U* h, |: p0 |
  • 常见问题:使用对象方法作为回调/事件处理程序这个问题的另一个常见表现是将对象方法用作回调/事件处理程序。函数是 JavaScript 中的一流公民,术语方法只是作为对象属性值函数的流行术语。但该函数并没有指向其包含对象的特定链接。
    3 M0 q* z8 I' p: d, {: J, m6 q! l
  • 考虑以下示例:[code]function Foo()      this.data = 42,   document.body.onclick = this.method;}Foo.prototype.method = function()      console.log(this.data);};* }5 |7 ?) j' ^, o
该函数this.method被分配到单击事件处理程序,但如果document.body单击 ,记录的值将为undefined,因为在事件处理程序内,this指的是document.body,而不是 的例子Foo。9 D" x) @" J0 L) H$ m: N/ h1 x
正如开头提到的,this什么取决于函数是如何工作的调用的,而不是它的样子定义的
/ `: I6 [* s- ?如下码如下所示,则该函数没有对象的隐藏引用可能更为明显:5 z0 ^( O6 v% a/ {* G  j, t' ]
    function method()      console.log(this.data);}function Foo()      this.data = 42,   document.body.onclick = this.method;}Foo.prototype.method = method;' v- X4 [  j9 L$ [# ?
解决该方法与上述方法相同:如果可用,则使用.bind显式绑定this到特定值. H" _* c4 ^5 J) t
    document.body.onclick = this.method.bind(this);
    " u! Q  t. s- t
或使用匿名函数作为回调/事件处理程序,对象 ( )this)分配给另一个变量,显式调用函数作为对象的方法:
: c; F: u* \3 B# ^' l

    8 d3 M  N' I/ L9 A# s4 g
  • var self = this;document.body.onclick = function() {    self.method();code]或使用箭头函数:[code]document.body.onclick = () => this.method();
    0 b8 r! j9 s8 d' D. e4 b7 v
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则