调用点(Call-site)

为了理解 this 绑定,我们不得不理解调用点:函数在代码中被调用的位置(不是被声明的位置)。我们必须考察调用点来回答这个问题:这个 this 指向什么?

一般来说寻找调用点就是:“找到一个函数是在哪里被调用的”,但它不总是那么简单,比如某些特定的编码模式会使 真正的 调用点变得不那么明确。

考虑 调用栈(call-stack) (使我们到达当前执行位置而被调用的所有方法的堆栈)是十分重要的。我们关心的调用点就位于当前执行中的函数 之前 的调用。

我们来展示一下调用栈和调用点:

  1. function baz() {
  2. // 调用栈是: `baz`
  3. // 我们的调用点是 global scope(全局作用域)
  4. console.log( "baz" );
  5. bar(); // <-- `bar` 的调用点
  6. }
  7. function bar() {
  8. // 调用栈是: `baz` -> `bar`
  9. // 我们的调用点位于 `baz`
  10. console.log( "bar" );
  11. foo(); // <-- `foo` 的 call-site
  12. }
  13. function foo() {
  14. // 调用栈是: `baz` -> `bar` -> `foo`
  15. // 我们的调用点位于 `bar`
  16. console.log( "foo" );
  17. }
  18. baz(); // <-- `baz` 的调用点

在分析代码来寻找(从调用栈中)真正的调用点时要小心,因为它是影响 this 绑定的唯一因素。

注意: 你可以通过按顺序观察函数的调用链在你的大脑中建立调用栈的视图,就像我们在上面代码段中的注释那样。但是这很痛苦而且易错。另一种观察调用栈的方式是使用你的浏览器的调试工具。大多数现代的桌面浏览器都内建开发者工具,其中就包含 JS 调试器。在上面的代码段中,你可以在调试工具中为 foo() 函数的第一行设置一个断点,或者简单的在这第一行上插入一个 debugger 语句。当你运行这个网页时,调试工具将会停止在这个位置,并且向你展示一个到达这一行之前所有被调用过的函数的列表,这就是你的调用栈。所以,如果你想调查this 绑定,可以使用开发者工具取得调用栈,之后从上向下找到第二个记录,那就是你真正的调用点。