Add new topic: this in TypeScript

This commit is contained in:
zhongsp 2016-01-31 19:31:04 +08:00
parent 1b987c5af2
commit ea0adf7a93
4 changed files with 134 additions and 1 deletions

View File

@ -35,6 +35,7 @@ TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
* [与其它构建工具整合](./doc/handbook/Integrating with Build Tools.md)
* [NPM包的类型](./doc/handbook/Typings for NPM Packages.md)
* Wiki
* [TypeScript里的this](./doc/handbook/this-in-TypeScript.md)
* [编码规范](./doc/handbook/coding_guidelines.md)
* [常见编译错误](./doc/handbook/Common Errors.md)
* [支持TypeScript的编辑器](./doc/handbook/TypeScript-Editor-Support.md)

View File

@ -26,6 +26,7 @@
* [与其它构建工具整合](./doc/handbook/Integrating with Build Tools.md)
* [NPM包的类型](./doc/handbook/Typings for NPM Packages.md)
* Wiki
* [TypeScript里的this](./doc/handbook/this-in-TypeScript.md)
* [编码规范](./doc/handbook/coding_guidelines.md)
* [常见编译错误](./doc/handbook/Common Errors.md)
* [支持TypeScript的编辑器](./doc/handbook/TypeScript-Editor-Support.md)

View File

@ -0,0 +1,129 @@
## 介绍
在JavaScript里还有TypeScript`this`关键字的行为与其它语言相比大为不同。这可能会很令人吃惊,特别是对于那些使用其它语言的用户凭借其直觉来想象`this`关键字的行为。
这篇文章会教你怎么识别及调试TypeScript里的`this`问题,并且提供了一些解决方案和各自的利弊。
## 典型症状和危险系数
丢失`this`上下文的典型症状包含:
* 类的某字段(`this.foo`)为`undefined`,但其它值没有问题
* `this`的值指向全局的`window`对象而不是类实例对象(在非严格模式下)
* `this`的值为`undefined`而不是类实例对象(严格模式下)
* 调用类方法(`this.doBa()`失败错误信息如“TypeError: undefined is not a function”“Object doesn't support property or method 'doBar'”或“this.doBar is not a function”
下面的代码应该出现在程序中:
* 事件监听,比如`window.addEventListener('click', myClass.doThing);`
* Promise解决比如`myPromise.then(myClass.theNextThing);`
* 第三方库回调,比如`$(document).ready(myClass.start);`
* 函数回调,比如`someArray.map(myClass.convert)`
* ViewModel类型的库里的类比如`<div data-bind="click: myClass.doSomething">`
* 可选包里的函数,比如`$.ajax(url, { success: myClass.handleData })`
## JavaScript里的`this`究竟是什么?
已经有大量的文章讲述了JavaScript里`this`关键字的危险性。查看[这里](http://www.quirksmode.org/js/this.html)[this one](http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/),或[这里](http://bjorn.tipling.com/all-this)。
当JavaScript里的一个函数被调用时你可以按照下面的顺序来推断出`this`指向的是什么(这些规则是按优先级顺序排列的):
* 如果这个函数是`function#bind`调用的结果,那么`this`指向的是传入`bind`的参数
* 如果函数是以`foo.func()`形式调用的,那么`this`值为`foo`
* 如果是在严格模式下,`this`将为`undefined`
* 否则,`this`将是全局对象(浏览器环境里为`window`
这些规则会产生与直觉相反的效果。比如:
```ts
class Foo {
x = 3;
print() {
console.log('x is ' + this.x);
}
}
var f = new Foo();
f.print(); // Prints 'x is 3' as expected
// Use the class method in an object literal
var z = { x: 10, p: f.print };
z.p(); // Prints 'x is 10'
var p = z.p;
p(); // Prints 'x is undefined'
```
## `this`的危险信号
你要注意地最大的危险信号是*在要使用类的方法时没有立即调用它*。任何时候你看到类方法被*引用了*却没有使用相同的表达式来*调用*时,`this`可能已经不对了。
例子:
```ts
var x = new MyObject();
x.printThing(); // SAFE, method is invoked where it is referenced
var y = x.printThing; // DANGER, invoking 'y()' may not have correct 'this'
window.addEventListener('click', x.printThing, 10); // DANGER, method is not invoked where it is referenced
window.addEventListener('click', () => x.printThing(), 10); // SAFE, method is invoked in the same expression
```
## 修复
可以通过一些方法来保持`this`的上下文。
### 使用实例函数
代替TypeScript里默认的*原型*方法,你可以使用一个*实例箭头函数*来定义类成员:
```ts
class MyClass {
private status = "blah";
public run = () => { // <-- note syntax here
alert(this.status);
}
}
var x = new MyClass();
$(document).ready(x.run); // SAFE, 'run' will always have correct 'this'
```
* 好与坏:这会创建额外的闭包对于每个类实例的每个方法。如果这个方法通常是正常调用的,那么这么做有点过了。然而,它经常会在回调函数里调用,让类实例捕获到`this`上下文会比在每次调用时都创建一个闭包来得更有效率一些。
* 好:其它外部使用者不可能忘记处理`this`上下文
* 好在TypeScript里是类型安全的
* 好:如果函数带参数不需要额外的工作
* 坏:派生类不能通过使用`super`调用基类方法
* 坏:在类与用户之前产生了额外的非类型安全的约束:明确了哪些方法提前绑定了以及哪些没有
### 本地的胖箭头
在TypeScrip里这里为了讲解添加了一些参数 :
```ts
var x = new SomeClass();
someCallback((n, m) => x.doSomething(n, m));
```
* 好与坏:内存/效能上的利弊与实例函数相比正相反
* 好在TypeScript100%的类型安全
* 好在ECMAScript 3里同样生效
* 好:你只需要输入一次实例名
* 坏你要输出2次参数名
* 坏:对于可变参数不起作用('rest'
### Function.bind
```ts
var x = new SomeClass();
// SAFE: Functions created from function.bind are always preserve 'this'
window.setTimeout(x.someMethod.bind(x), 100);
```
* 好与坏:内存/效能上的利弊与实例函数相比正相反
* 好:如果函数带参数不需要额外的工作
* 坏目前在TypeScript里不是类型安全的
* 坏只在ECMAScript 5里生效
* 坏你要输入2次实例名

View File

@ -47,6 +47,7 @@ TypeScript目前还在积极的开发完善之中不断地会有新的特性
* [与其它构建工具整合](./doc/handbook/Integrating with Build Tools.html)
* [NPM包的类型](./doc/handbook/Typings for NPM Packages.html)
* Wiki
* [TypeScript里的this](./doc/handbook/this-in-TypeScript.html)
* [编码规范](./doc/handbook/coding_guidelines.html)
* [常见编译错误](./doc/handbook/Common Errors.html)
* [支持TypeScript的编辑器](./doc/handbook/TypeScript-Editor-Support.html)
@ -57,7 +58,8 @@ TypeScript目前还在积极的开发完善之中不断地会有新的特性
## 主要修改
* 2016-01-24 新增章节:[发展路线图](./doc/handbook/Roadmap.md)
* 2016-01-31 新增章节:[TypeScript里的this](./doc/handbook/this-in-TypeScript.html)
* 2016-01-24 新增章节:[发展路线图](./doc/handbook/Roadmap.html)
* 2016-01-23 新增章节:[编码规范](./doc/handbook/coding_guidelines.html)
* 2016-01-23 新增章节:[架构概述](./doc/handbook/Architectural-Overview.html)
* 2015-12-27 新增章节:[结合ASP.NET v5使用TypeScript](./doc/handbook/Using-TypeScript-With-ASP.NET-5.html)