|
我有注册事件处理程序的构造函数:! `* 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 Kfunction 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" R2 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
|
|