02this 与绑定

this 是 JS 里最「看脸色」的关键字——同样一行 this.name, 在不同调用方式下可能指向完全不同的对象。本课把四条绑定规则、call/apply/bind、 箭头函数的例外一次讲透。

约 15 分钟 4 个动手实验 面试高频

一、为什么需要 this

写一个「打印用户名」的函数时,不想每次把对象当参数传来传去, 就用 this 指代「当前操作的对象」。问题是: this 到底指向谁,由「怎么调用」决定,不由「写在哪」决定。

把方法「摘出来」单独调用,this 就丢了。 这是写组件、传回调时最常见的 bug 来源。

二、四条绑定规则(优先级从低到高)

1默认绑定

独立调用 fn():非严格模式 this = window;严格模式 = undefined。

2隐式绑定

作为对象方法调用 obj.fn():this = obj。看「.」前面是谁。

3显式绑定

call / apply / bind 强制指定 this,优先级高于隐式。

4new 绑定

new Fn() 时 this = 新建的实例对象,优先级最高。

四条规则各跑一遍:点按钮看同一个函数在不同调用方式下 this 指向谁

三、call / apply / bind 三件套

方法参数是否立刻调用返回
fn.call(thisArg, a, b) 参数逐个传 ✓ 立刻执行 函数返回值
fn.apply(thisArg, [a,b]) 参数装数组 ✓ 立刻执行 函数返回值
fn.bind(thisArg, a) 可预填参数 ✗ 返回新函数 绑好 this 的新函数
实用场景:借数组方法处理类数组、bind 预填参数做「加法工厂」

四、箭头函数:没有自己的 this

箭头函数不绑定 this,它会沿作用域链向外找「定义时」外层的 this。 这一条规则解决了「回调里 this 丢了」的 90% 问题。

普通函数 vs 箭头函数的 this
普通函数箭头函数
this调用时决定(四规则)定义时外层 this(词法)
arguments有无(用 ...args)
new可以不可以当构造函数
prototype有无
适用方法、构造函数、需要动态 this回调、map/filter、简短逻辑
同一段延迟逻辑:普通函数 vs 箭头函数,看 this.name 差异
需要动态 this 的场景(比如给按钮绑定时想拿 this = 按钮), 用普通函数或事件里的 event.currentTarget,不要用箭头。

五、常见踩坑对照

写法this 指向坑
obj.fn()obj—
const f = obj.fn; f()window / undefined方法被摘出来
obj.fn.call(other)other—
setTimeout(obj.fn, 0)window / undefined传的是函数引用
setTimeout(() => obj.fn(), 0)obj正确:包一层
new Fn()新实例—
btn.addEventListener('click', fn)btnfn 须是普通函数
btn.addEventListener('click', () => …)外层箭头拿不到按钮

六、严格模式下的 this

'use strict' 下,独立调用的函数 this 是 undefined 而不是 window。 ES Module 默认就是严格模式——所以模块里的 fn() this = undefined。

七、和闭包 / 原型的连接

  • 闭包保存的是变量;bind 保存的是 this——两者常一起用。
  • 原型方法里的 this 依赖调用方式:arr.map(fn) 时 fn 的 this 默认 undefined。
  • 写 class 时,方法里的 this 依赖实例调用;传作回调要 .bind(this) 或改箭头。

八、本章小结

  • this 由调用方式决定,不是由定义位置决定(箭头函数除外)。
  • 四规则优先级:new > 显式(call/apply/bind)> 隐式(obj.fn)> 默认。
  • call/apply 立刻调用;bind 返回新函数、可预填参数。
  • 箭头函数没有自己的 this,沿定义处外层取——回调首选。
  • 方法被摘出来单独调用会丢 this;setTimeout(obj.fn) 是经典 bug。
  • 严格模式 / 模块中独立调用 this = undefined。
动手练习: ① 用 bind 把一个「获取用户名」方法绑到指定对象后再当回调传给 setTimeout; ② 写一个 Person 构造函数,用 new 创建两个实例并证明 this 各自独立; ③ 把一个用了 arguments 的普通函数改写成箭头函数 + 剩余参数。