Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
109 views
in Technique[技术] by (71.8m points)

TypeScript "this" scoping issue when called in jquery callback

I'm not sure of the best approach for handling scoping of "this" in TypeScript.

Here's an example of a common pattern in the code I am converting over to TypeScript:

class DemonstrateScopingProblems {
    private status = "blah";
    public run() {
        alert(this.status);
    }
}

var thisTest = new DemonstrateScopingProblems();
// works as expected, displays "blah":
thisTest.run(); 
// doesn't work; this is scoped to be the document so this.status is undefined:
$(document).ready(thisTest.run); 

Now, I could change the call to...

$(document).ready(thisTest.run.bind(thisTest));

...which does work. But it's kinda horrible. It means that code can all compile and work fine in some circumstances, but if we forget to bind the scope it will break.

I would like a way to do it within the class, so that when using the class we don't need to worry about what "this" is scoped to.

Any suggestions?

Update

Another approach that works is using the fat arrow:

class DemonstrateScopingProblems {
    private status = "blah";

    public run = () => {
        alert(this.status);
    }
}

Is that a valid approach?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You have a few options here, each with its own trade-offs. Unfortunately there is no obvious best solution and it will really depend on the application.

Automatic Class Binding
As shown in your question:

class DemonstrateScopingProblems {
    private status = "blah";

    public run = () => {
        alert(this.status);
    }
}
  • Good/bad: This creates an additional closure per method per instance of your class. If this method is usually only used in regular method calls, this is overkill. However, if it's used a lot in callback positions, it's more efficient for the class instance to capture the this context instead of each call site creating a new closure upon invoke.
  • Good: Impossible for external callers to forget to handle this context
  • Good: Typesafe in TypeScript
  • Good: No extra work if the function has parameters
  • Bad: Derived classes can't call base class methods written this way using super.
  • Bad: The exact semantics of which methods are "pre-bound" and which aren't create an additional non-typesafe contract between your class and its consumers.

Function.bind
Also as shown:

$(document).ready(thisTest.run.bind(thisTest));
  • Good/bad: Opposite memory/performance trade-off compared to the first method
  • Good: No extra work if the function has parameters
  • Bad: In TypeScript, this currently has no type safety
  • Bad: Only available in ECMAScript 5, if that matters to you
  • Bad: You have to type the instance name twice

Fat arrow
In TypeScript (shown here with some dummy parameters for explanatory reasons):

$(document).ready((n, m) => thisTest.run(n, m));
  • Good/bad: Opposite memory/performance trade-off compared to the first method
  • Good: In TypeScript, this has 100% type safety
  • Good: Works in ECMAScript 3
  • Good: You only have to type the instance name once
  • Bad: You'll have to type the parameters twice
  • Bad: Doesn't work with variadic parameters

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...