深入理解 JavaScript 箭头函数的 this:为什么 DOM 事件不推荐用箭头函数?

深入理解 JavaScript 箭头函数的 this:为什么 DOM 事件不推荐用箭头函数?

在学习 JavaScript 时,很多人都会被 this 搞得一头雾水。而当箭头函数出现之后,this 的行为又发生了"根本性变化",让原本就复杂的规则更加扑朔迷离。

这篇文章系统整理两个非常核心的问题:

  1. 箭头函数里面到底有没有 this
  2. 为什么 DOM 事件回调函数通常不推荐使用箭头函数?

如果你对 this 的指向、事件绑定、回调函数执行机制还不够清晰,这篇笔记会帮你彻底理顺。


一、先说结论

1)箭头函数有没有 this

箭头函数:

  • 不会创建自己的 this
  • 只会继承外层作用域的 this
  • this函数定义时确定
  • 永远不会被调用方式改变

本质:

kotlin 复制代码
箭头函数的 this 是"继承的",不是"绑定的"

2)DOM 事件回调推荐用箭头函数吗?

通常不推荐,尤其是:

  • 你需要使用 this 指向触发事件的元素
  • 你需要访问 DOM 节点本身

因为:

ini 复制代码
事件回调使用普通函数 → this = 触发事件的元素
事件回调使用箭头函数 → this = 外层作用域(通常是 window)

这就是为什么很多代码"明明写在按钮事件里",却拿不到按钮本身。


二、普通函数的 this 是怎么决定的?

普通函数的 this运行时决定的,遵循一个非常重要的规则:

kotlin 复制代码
谁调用函数,this 就指向谁

看例子:

javascript 复制代码
const obj = {
  name: 'andy',
  sayHi: function () {
    console.log(this)
  }
}

obj.sayHi()

执行时:

ini 复制代码
调用者是 obj
所以 this = obj

这叫:

隐式绑定


三、箭头函数的 this 为什么完全不同?

来看箭头函数版本:

javascript 复制代码
const obj = {
  name: 'andy',
  sayHi: () => {
    console.log(this)
  }
}

obj.sayHi()

很多人以为:

ini 复制代码
this = obj

但实际结果(浏览器中):

ini 复制代码
this = window

为什么?


根本原因:箭头函数没有自己的 this

箭头函数不会进行 this 绑定,它只会:

kotlin 复制代码
向外查找一层作用域的 this

这叫:

词法作用域绑定(lexical this)

也就是:

kotlin 复制代码
写在哪个作用域
就继承哪个作用域的 this

而不是:

复制代码
谁调用决定

举个真实执行过程

javascript 复制代码
const obj = {
  sayHi: () => {
    console.log(this)
  }
}

箭头函数定义位置:

复制代码
全局作用域

浏览器中:

ini 复制代码
全局作用域 this = window

所以最终:

ini 复制代码
箭头函数 this = window

即使这样调用:

scss 复制代码
obj.sayHi()

也不会改变。

因为箭头函数根本不看调用方式。


四、普通函数 vs 箭头函数(本质对比)

特性 普通函数 箭头函数
是否有自己的 this 没有
this 什么时候确定 运行时 定义时
是否受调用方式影响
能否被 call/apply/bind 修改 可以 不可以
是否适合对象方法 非常适合 不推荐
是否适合回调函数 可以 非常适合

五、为什么 DOM 事件不推荐箭头函数?

这是开发中最常踩的坑。

先看正确写法:

javascript 复制代码
button.addEventListener('click', function () {
  console.log(this)
})

输出:

复制代码
触发点击的按钮元素

原因:

浏览器会把 this 自动绑定为:

复制代码
事件触发元素

这是 DOM 事件的默认规则。


再看箭头函数版本:

javascript 复制代码
button.addEventListener('click', () => {
  console.log(this)
})

输出:

javascript 复制代码
window

为什么?

因为:

箭头函数的 this 来自外层作用域。

而不是事件系统绑定的。

也就是说:

kotlin 复制代码
DOM 想给你绑定 this
箭头函数:不用,我已经有了

所以绑定失败。


六、真实开发中的典型错误

很多人写:

javascript 复制代码
button.addEventListener('click', () => {
  this.style.color = 'red'
})

结果报错:

arduino 复制代码
Cannot read property 'style' of undefined

因为:

ini 复制代码
this = window

window 没有 style。


正确写法:

javascript 复制代码
button.addEventListener('click', function () {
  this.style.color = 'red'
})

七、那箭头函数什么时候适合用?

箭头函数最适合:

1)回调函数

比如:

javascript 复制代码
setTimeout(() => {
  console.log(this)
}, 1000)

常见于:

  • 定时器
  • Promise
  • 数组方法
  • 异步回调

原因:

kotlin 复制代码
避免 this 丢失

2)需要继承外层 this

经典场景:

javascript 复制代码
class Person {
  constructor() {
    this.name = 'Tom'

    setTimeout(() => {
      console.log(this.name)
    }, 1000)
  }
}

如果用普通函数:

javascript 复制代码
this 会变成 window

箭头函数可以自动继承类实例。


八、一个超级重要的判断口诀

如果你需要:

kotlin 复制代码
动态 this

用普通函数。

如果你需要:

kotlin 复制代码
稳定 this(继承外层)

用箭头函数。


九、对象方法为什么不建议箭头函数?

因为对象方法通常需要:

ini 复制代码
this = 当前对象

但箭头函数做不到。

javascript 复制代码
const user = {
  name: 'Lucy',
  sayHi: () => {
    console.log(this.name)
  }
}

输出:

javascript 复制代码
undefined

因为 this 不是 user。


相关推荐
小爬的老粉丝1 小时前
JavaScript 纯前端预览 WPS:先识别容器,再路由解析器
前端·javascript·wps
计算机魔术师1 小时前
新兴多智能体系统的模式与问题
前端
用户059540174462 小时前
AI Agent 上下文污染踩坑实录:用 pytest + Redis 揪出 3 类记忆串号 bug,排查 6 小时
前端·css
满栀5852 小时前
状态管理:Redux、Vuex、Pinia 核心区别
前端·javascript·typescript
一拳不是超人3 小时前
DeepSeek Harness 为什么敢说"一切皆插件"?拆透 Cordis 引擎的五大核心机制
前端·人工智能·agent
IT_陈寒3 小时前
Python的GIL让我多写了500行代码
前端·人工智能·后端
风骏时光牛马3 小时前
AI智能体能力调度微服务
前端
大龄码农有梦想4 小时前
Vue + BPMN.js + Camunda:搭建企业级流程设计器完整实践
javascript·vue.js·流程设计器·bpmn.js·bpmn·流程审批·工作流设计器
Eloudy5 小时前
ReAct 原理简介
前端·javascript·人工智能·react.js·agent·gpu
ZJU_统一阿萨姆6 小时前
【DSH】如何将 DeepSeek Harness 嵌入生产环境?万字解构 DeepSeek Agent Harness 的运行机制与安全边界
前端·javascript·安全