javascript的this指向什么_如何控制this的绑定?

普通函数直接调用时,非严格模式下this指向全局对象(浏览器为window,Node为global),严格模式下为undefined;箭头函数无自身this,继承定义时词法作用域的this值,且不可被call/apply/bind修改。

普通函数调用时 this 指向什么?

直接调用 fn(),非严格模式下 this 指向全局对象(浏览器中是 window,Node.js 中是 global);严格模式下为 undefined。这是最容易出错的场景——你以为在对象方法里写了个函数,结果单独拎出来调用,this 就丢了。

  • 对象方法内定义的普通函数(非箭头),this 不继承外层对象,仍按调用方式决定
  • 事件回调、定时器回调、异步回调(如 setTimeout)里直接写 fn()this 也默认丢失
  • 避免写 obj.method(); fn(); 然后指望 fn 里的 thisobj —— 它不是

箭头函数的 this 是怎么确定的?

箭头函数没有自己的 this,它沿用定义时所在词法作用域的 this 值,且无法被 call/apply/bind 改写。这使得它特别适合用在回调中保持上下文。

const obj = {
  name: 'alice',
  regular() {
    console.log(this.name); // 'alice'
    setTimeout(function() {
      console.log(this.name); // undefined(非严格)或报错(严格)
    }, 100);
    setTimeout(() => {
      console.log(this.name); // 'alice',继承外层 regular 的 this
    }, 100);
  }
};
  • 箭头函数不能用作构造函数(new 会报错)
  • 没有 arguments 对象,要用剩余参数 ...args
  • 不能用 yield,不支持生成器语法

如何用 call/apply/bind 显式绑定 this?

三者都用于手动指定函数执行时的 this 值,区别只在参数传入方式:call 用逗号分隔,apply 用数组,bind 返回新函数(不立即执行)。

function greet(greeting, punctuation) {
  return `${greeting}, ${this.name}${punctuation}`;
}
const person = { name: 'bob' };

greet.call(person, 'Hello', '!');     // "Hello, bob!"
greet.apply(person, ['Hi', '?']);     // "Hi, bob?"
const boundGreet = greet.bind(person, 'Hey');
boundGreet('.');                      // "Hey, bob."
  • bind 常用于预设部分参数(柯里化),也常用来修复事件处理器中的 this
  • callapply 多用于借用方法,比如 Array.prototype.slice.call(arguments)
  • 注意:箭头函数对这三者完全免疫,调用无效

class 方法里的 this 为什么经常 undefined?

类中定义的方法默认是“普通函数”,如果从对象上取出来单独调用(如传给事件监听器、定时器、Promise 回调),this 就会丢失。这不是 class 特性问题,而是函数调用规则本身导致的。

class Button {
  constructor() {
    this.label = 'click me';
  }
  handleClick() {
    console.log(this.label); // 若直接 onclick="handleClick()" 或作为回调传入,这里会是 undefined
  }
  init() {
    // ❌ 错误:this.handleClick 被提取后失去绑定
    document.addEventListener('click', this.handleClick);

    // ✅ 正确:用 bind / 箭头函数 / 包装函数
    document.addEventListener('click', this.handleClick.bind(this));
    // 或
    document.addEventListener('click', () => this.handleClick());
    // 或
    document.addEventListener('click', (e) => this.handleClick(e));
  }
}
  • 类字段语法 + 箭头函数写法(handleClick = () => {})可自动绑定,但每次实例化都会创建新函数,有内存开销
  • React 类组件中常见该问题,函数组件配合 useCallback 是更现代的解法
  • 不要依赖编译器(如 Babel)自动插 bind,明确写出绑定逻辑才可控
真正难的不是记住规则,是在嵌套回调、第三方库钩子、动态注册场景里,一眼识别出哪个函数正在以什么方式被调用。this 绑定问题几乎从不报错,只默默返回 undefined 或指向错误对象——查起来比语法错误还费时间。