Skip to content

回调函数里的 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的指向可能被隐式绑定、显式绑定或使用箭头函数来保持。

  1. 隐式绑定:当回调函数是作为对象方法调用时,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.

在这个示例中,callbackFunctionExample类的方法。在process方法中,我们使用setTimeout来调度执行callbackFunction。由于callbackFunction作为对象方法调用,this关键字会隐式绑定到example实例上,因此可以访问实例属性name

  1. 显式绑定:您可以使用bindcallapply方法来显式地指定回调函数中的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对象。

  1. 箭头函数:箭头函数具有自动绑定的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实例。

仅用于培训和测试,通过使用本站代码内容随之而来的风险与本站无关。版权所有,未经授权请勿转载,保留一切权利。
ICP备案号:滇ICP备15009214号-13   公安网备:滇公网安备 53312302000061号