可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I know this is probably painfully basic, but i am having a tough time wrapping my head around it.
class Main { constructor() { requestAnimationFrame(this.update); //fine } update(): void { requestAnimationFrame(this.update); //error, because this is window } }
It appears to be the case that I need a proxy, so lets say using Jquery
class Main { constructor() { this.updateProxy = $.proxy(this.update, this); requestAnimationFrame(this.updateProxy); //fine } updateProxy: () => void update(): void { requestAnimationFrame(this.updateProxy); //fine } }
But coming from an Actionscript 3 background, I am not really sure what is happening here. Sorry I am not sure where Javascript begins and TypeScript ends.
updateProxy: () => void
And also, I am not convinced I am doing this right. The last thing I want is most of my class having a a() function which needs to be accessed with aProxy()
as I feel I am writing the same thing twice? Is it normal?
回答1:
If you want this
captured the TypeScript way of doing this is via arrow functions. To quote Anders:
The this
in arrow functions is lexically scoped
Here is the way I like to use this to my advantage:
class test{ // Use arrow functions func1=(arg:string)=>{ return arg+" yeah" + this.prop; } func2=(arg:number)=>{ return arg+10 + this.prop; } // some property on this prop = 10; }
View this in the TypeScript Playground
You can see that in the generated JavaScript this
is captured outside the function call:
var _this = this; this.prop = 10; this.func1 = function (arg) { return arg + " yeah" + _this.prop; };
so the this
value inside the function call (which could be window
) would not be used.
To learn more: “Understanding this
回答2:
If you write your methods like this, 'this' will be treated the way you expect.
class Main { constructor() { requestAnimationFrame(() => this.update()); } update(): void { requestAnimationFrame(() => this.update()); } }
Another option would be to bind 'this' to the function call:
class Main { constructor() { requestAnimationFrame(this.update.bind(this)); } update(): void { requestAnimationFrame(this.update.bind(this)); } }
回答3:
The problem arises when you pass a function as a callback. By the time the callback has executed the value of "this" could have changed to the Window, the control invoking the callback, or something else.
Make sure you always use a lambda expression at the point you pass a reference to the function to be called back. For example
public addFile(file) { this.files.push(file); } //Not like this someObject.doSomething(addFile); //but instead, like this someObject.doSomething( (file) => addFile(file) );
This compiles to something like
this.addFile(file) { this.files.push(file); } var _this = this; someObject.doSomething(_this.addFile);
Because the addFile function is being called on a specific object reference (_this) it does not use the "this" of the invoker but instead the value of _this.
回答4:
See page 72 of the typescript language specification https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.pdf?raw=true
Arrow Function Expressions
In the example
class Messenger { message = "Hello World"; start() { setTimeout(() => alert(this.message), 3000); } }; var messenger = new Messenger(); messenger.start();
the use of an arrow function expression causes the callback to have the same this as the surrounding ‘start’ method. Writing the callback as a standard function expression it becomes necessary to manually arrange access to the surrounding this, for example by copying it into a local variable:
This is the actual generated Javascript:
class Messenger { message = "Hello World"; start() { var _this = this; setTimeout(function() { alert(_this.message); }, 3000); } };
回答5:
In short, the this keyword always has a reference to the object that called the function.
In Javascript, since functions are just variables, you can pass them around.
Example:
var x = { localvar: 5, test: function(){ alert(this.localvar); } }; x.test() // outputs 5 var y; y.somemethod = x.test; // assign the function test from x to the 'property' somemethod on y y.test(); // outputs undefined, this now points to y and y has no localvar y.localvar = "super dooper string"; y.test(); // outputs super dooper string
When you do the following with jQuery:
$.proxy(this.update, this);
What you are doing is overriding that context. Behind the scenes jQuery will guive you this:
$.proxy = function(fnc, scope){ return function(){ return fnc.apply(scope); // apply is a method on a function that calls that function with a given this value } };