Appearance
回调函数里的 this 参数
在回调函数中,this 关键字的指向可以根据几个不同的因素而有所不同。对于回调函数,this 的指向可能被隐式绑定、显式绑定或使用箭头函数来保持。常见的情况包括箭头函数和函数绑定。所以,当你将一个函数传递到某个库函数里在稍后被调用时,你可能也见到过回调函数里的 this 会报错。 因为当回调函数被调用时,它会被当成一个普通函数调用,this 将为 undefined。 稍做改动,你就可以通过 this 参数来避免错误。 首先,库函数的作者要指定 this 的类型:
ts
interface UIElement {
addClickListener(onclick: (this: void, e: Event) => void): void;
}
this: void 意味着 addClickListener 期望 onclick 是一个函数且它不需要一个 this 类型。 然后,为调用代码里的 this 添加类型注解:
ts
class Handler {
info: string;
onClickBad(this: Handler, e: Event) {
// oops, used this here. using this callback would crash at runtime
this.info = e.message;
}
}
let h = new Handler();
uiElement.addClickListener(h.onClickBad); // error!
指定了 this 类型后,你显式声明 onClickBad 必须在 Handler 的实例上调用。 然后 TypeScript 会检测到 addClickListener 要求函数带有 this: void。 改变 this 类型来修复这个错误:
ts
class Handler {
info: string;
onClickGood(this: void, e: Event) {
// can't use this here because it's of type void!
console.log("clicked!");
}
}
let h = new Handler();
uiElement.addClickListener(h.onClickGood);
因为 onClickGood 指定了 this 类型为 void,因此传递 addClickListener 是合法的。 当然了,这也意味着不能使用 this.info. 如果你两者都想要,你不得不使用箭头函数了:
ts
class Handler {
info: string;
onClickGood = (e: Event) => {
this.info = e.message;
};
}
这是可行的因为箭头函数不会捕获 this,所以你总是可以把它们传给期望 this: void 的函数。 缺点是每个 Handler 对象都会创建一个箭头函数。 另一方面,方法只会被创建一次,添加到 Handler 的原型链上。 它们在不同 Handler 对象间是共享的。
隐式绑定,显式绑定,箭头函数 的指向差异
在 TypeScript 中,在回调函数中,this
关键字的指向可以根据几个不同的因素而有所不同。对于回调函数,this
的指向可能被隐式绑定、显式绑定或使用箭头函数来保持。
- 隐式绑定:当回调函数是作为对象方法调用时,
this
关键字会隐式绑定到调用该方法的对象上。
typescript
class Example {
private name: string = "Alice";
callbackFunction() {
console.log(`Hello, ${this.name}.`);
}
process() {
setTimeout(this.callbackFunction, 1000);
}
}
const example = new Example();
example.process(); // 输出:Hello, Alice.
在这个示例中,callbackFunction
是Example
类的方法。在process
方法中,我们使用setTimeout
来调度执行callbackFunction
。由于callbackFunction
作为对象方法调用,this
关键字会隐式绑定到example
实例上,因此可以访问实例属性name
。
- 显式绑定:您可以使用
bind
、call
或apply
方法来显式地指定回调函数中的this
关键字的值。这样可以确保this
指向您想要的对象。
typescript
function callbackFunction() {
console.log(`Hello, ${this.name}.`);
}
const object = {
name: "Alice",
};
const boundFunction = callbackFunction.bind(object);
setTimeout(boundFunction, 1000); // 输出:Hello, Alice.
在这个示例中,callbackFunction
是一个普通函数,但我们使用bind
方法将其绑定到object
上。然后我们使用setTimeout
来调度执行boundFunction
,此时boundFunction
中的this
关键字被绑定到object
对象。
- 箭头函数:箭头函数具有自动绑定的
this
值,指向定义该函数时的上下文。
typescript
class Example {
private name: string = "Alice";
process() {
setTimeout(() => {
console.log(`Hello, ${this.name}.`);
}, 1000);
}
}
const example = new Example();
example.process(); // 输出:Hello, Alice.
在这个示例中,我们使用了箭头函数来定义setTimeout
的回调函数。箭头函数会捕获定义时的上下文,因此this
关键字在回调函数中仍然指向Example
实例。