跳到主要内容

this:一张规则表讲清绑定优先级,箭头函数为什么“没 this”?

面试速答(30 秒版 TL;DR)

  • this 不是“定义时决定”,而是调用时按规则绑定(箭头函数例外)。
  • 绑定规则优先级(从高到低):new 绑定 > bind 硬绑定 > call/apply 显式绑定 > 隐式绑定(obj.fn()) > 默认绑定(严格模式 undefined,非严格模式 window/globalThis)。
  • 箭头函数没有自己的 this:它捕获外层词法作用域的 this(lexical this),call/apply/bind 改不了。
  • 事件处理、回调函数、解构赋值后的方法调用是 this 丢失的高频坑;用 bind、箭头函数、或显式调用修复。

心智模型:this 只看“怎么调用”

不要背“this 指向谁”,背“调用表达式长什么样”更稳。

// 同一个函数,不同调用方式,this 不同
function f() {
return this;
}

f(); // 默认绑定:严格模式 undefined;非严格模式 globalThis
({ f }).f(); // 隐式绑定:{ f }
f.call({ x: 1 }); // 显式绑定:{ x: 1 }
new f(); // new 绑定:新对象

绑定优先级流程图(背这一张)


隐式绑定的坑:方法被“拿出来”就丢了

const obj = {
x: 1,
getX() {
return this.x;
},
};

obj.getX(); // 1

const getX = obj.getX;
getX(); // 严格模式:TypeError(this 为 undefined);非严格:undefined

修复方式(面试常见答法):

  • bind 固定:const getX = obj.getX.bind(obj)
  • 用包装函数显式调用:() => obj.getX()
  • 在类里用字段箭头函数(见 class 章节):method = () => { ... }

箭头函数:为什么“没 this”,却又能用 this?

箭头函数的 this 来自外层最近的普通函数/全局 this

const obj = {
x: 1,
a() {
const arrow = () => this.x;
return arrow();
},
};

obj.a(); // 1

关键点:

  • 箭头函数的 this 不是运行时绑定,因此 arrow.call({ x: 2 }) 也不会变。
  • 箭头函数也没有 argumentsprototype,不能 new

典型题 & 标准答法

Q1:obj.fn() 一定让 this === obj 吗?

不一定。只要“调用表达式”不是 obj.fn(),隐式绑定就可能丢失,例如:

const obj = { x: 1, fn() { return this.x; } };
const { fn } = obj;
fn(); // this 丢失

Q2:setTimeout(obj.fn, 0)this 是什么?

this 丢失。因为传给定时器的是“裸函数引用”,等同于默认绑定(严格模式 undefined)。


常见追问

  • call/apply/bind 区别:call 传参列表;apply 传参数组;bind 返回新函数并固定 this
  • null/undefined 作为 call/apply 的 thisArg:非严格模式会被替换为 globalThis;严格模式保持 null/undefined

易错点/坑

  • this 不是指向“函数定义的对象”,而是指向“调用点绑定的对象”。
  • 回调函数(事件、Promise、数组遍历)最容易丢 this,尤其是把方法当参数传递。

速记要点(可背诵)

  • this 看调用点;箭头函数看外层作用域。
  • 优先级:new > bind > call/apply > obj.fn() > 默认绑定。