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实例。
