梗概

  • JavaScript函数执行的上下文(context)不是由函数定义的位置决定的,而是由函数调用的位置决定的
  • 理解函数执行上下文对于掌握JavaScript中的[build::JavaScript this关键字]和闭包至关重要

关键特性

  • 函数执行上下文决定了函数内部的this指向
  • 回调函数中调用另一个函数时,上下文是定义回调函数时的上下文,而非被调用函数定义的上下文
  • 箭头函数与普通函数不同,它会保留定义时的上下文,不会创建自己的this

示例

// 注册节点右键菜单事件
newGraph.on('node:contextmenu', ({ cell, e }) => {
  handleNodeContextMenu(cell, e);
});

在这个例子中:

  • 回调函数({ cell, e }) => { handleNodeContextMenu(cell, e); }中调用了handleNodeContextMenu函数
  • 此时handleNodeContextMenu函数的执行上下文是定义回调函数时的上下文
  • 而不是定义handleNodeContextMenu函数时的上下文

常见场景

1. 对象方法

const user = {
  name: 'Alice',
  greet() {
    console.log(`Hello, ${this.name}`);
  }
};
 
user.greet(); // 输出: "Hello, Alice" - this指向user对象
const greetFunc = user.greet;
greetFunc(); // 输出: "Hello, undefined" - this指向全局对象(或undefined在严格模式)

2. 回调函数

const button = document.getElementById('myButton');
const user = {
  name: 'Bob',
  handleClick() {
    console.log(`Button clicked by ${this.name}`);
  }
};
 
// 错误方式
button.addEventListener('click', user.handleClick); // this会指向button而非user
 
// 正确方式1: 使用箭头函数
button.addEventListener('click', () => user.handleClick()); 
 
// 正确方式2: 使用bind
button.addEventListener('click', user.handleClick.bind(user));

改变函数上下文的方法

  • use::call
  • apply(thisArg, argsArray): 立即调用函数并指定this,参数以数组形式传入
  • bind(thisArg, ...args): 返回一个新函数,this被永久绑定到指定值