← 返回题目列表

箭头函数和普通函数有什么区别?

高频 中等 第 6 / 28 题 更新于 2026/07/27
ES6箭头函数this

简化版

箭头函数语法更短,没有自己的 thisargumentssupernew.target,不能作为构造函数,也没有 prototype。它适合回调和函数式写法,不适合对象方法、构造函数和需要动态 this 的场景。

详细版

箭头函数最大的差异是词法 this

function Timer() {
  this.count = 0;
  setInterval(() => {
    this.count++;
  }, 1000);
}

回调里的 this 继承外层 Timer 的 this。

不适合这样写:

const obj = {
  name: 'Tom',
  say: () => console.log(this.name),
};

这里 this 不指向 obj。另外箭头函数不能 new,也不能用 arguments,需要参数集合时用剩余参数 ...args

完整版教学

一、箭头函数不是普通函数的简写版

箭头函数确实语法短,但它更重要的设计是“捕获外层 this”。普通函数的 this 看调用方式,箭头函数的 this 看定义位置。

这让它非常适合数组方法和异步回调:

items.map(item => item.id);

二、为什么不能作为构造函数

构造函数需要通过 new 创建实例,并把 this 绑定到新对象。箭头函数没有自己的 this,也没有 prototype,所以不能 new

const Foo = () => {};
new Foo(); // TypeError

三、arguments 的替代方案

箭头函数没有自己的 arguments,可以用剩余参数:

const sum = (...nums) => nums.reduce((a, b) => a + b, 0);

这种写法更明确,也是真数组,不需要再转换。

四、使用边界

对象方法通常用普通函数,因为方法经常需要 this 指向调用者。类方法也不要随意写成箭头属性,除非明确需要绑定实例 this,并且能接受每个实例创建一份函数的成本。选择时要同时回答两个问题:this 是否需要动态接收者,以及函数是否值得在所有实例间共享。

五、面试追问与工程落地

箭头函数常见追问是“它有没有自己的 arguments”。答案是没有,它访问到的是外层函数的 arguments。现代写法应该用剩余参数 ...args,这不仅更清晰,而且拿到的是真数组。

还会问“箭头函数适不适合写 class 方法”。如果写成类字段箭头函数,它会绑定实例 this,适合传给回调避免 bind;但每个实例都会创建一份函数,不能像原型方法那样共享。组件数量很大或方法很多时,要注意内存成本。

工程里对象方法不要默认写箭头函数,尤其是需要通过调用者决定 this 的 API。比如事件系统、插件钩子、对象字面量方法,都要先判断 this 是否需要动态绑定。

六、用调用结果判断 this 与构造能力

判断箭头函数行为时,不要只看它写在哪里,而要找“定义它时最近一层拥有 this 的非箭头函数或模块环境”。箭头函数不会在调用时执行普通函数的 this 绑定流程,callapplybind 传入的新接收者也覆盖不了这个词法 this。同理,它没有自己的 argumentssupernew.target,这些名称都沿词法环境向外查找。

function Counter() {
  this.value = 1
  this.read = () => this.value
}
const counter = new Counter()
console.log(counter.read.call({ value: 99 })) // 1
console.log(Object.hasOwn(counter, 'read'))   // true
检查项普通函数箭头函数
call 能否改 this不能
是否有 prototype通常有没有
能否配合 new取决于是否有 [[Construct]]不能
arguments 来源本次调用外层词法环境

上例创建 1000 个 Counter 实例时,也会创建 1000 个 read 函数;若方法放在原型上,通常只共享 1 份函数。这不是说实例箭头方法一定错误,而是需要用“稳定绑定”换取相应的实例内存成本。

面试中最好先给出词法绑定规则,再分别说明事件回调、对象方法和类字段三种场景,不能笼统回答“箭头函数的 this 永远指向 window”。

七、常见误区与追问

  • 误区:箭头函数的 this 永远指向全局对象。 它捕获外层词法 this;ES 模块顶层的 thisundefined,浏览器事件回调中的外层环境也可能不同。
  • 误区:用 bind 可以永久修正箭头函数的 this。 bind 可以预置参数,但无法替换箭头函数已经捕获的 this
  • 误区:箭头函数只是写法更短。 它缺少自己的 thisarguments 和构造能力,语义并不等同于普通函数表达式。
  • 追问:箭头函数为什么不能 new? 它没有 [[Construct]] 内部方法,也没有供实例继承的默认 prototype,调用 new 会抛出 TypeError
  • 追问:对象方法适合直接写成箭头函数吗? 若方法需要通过 obj.method() 取得 obj,通常不适合;箭头函数不会因点调用而绑定接收者。
  • 追问:类字段箭头方法有什么代价? 每个实例都会创建并持有一份函数,换来回调传递后仍保持实例 this
  • 追问:没有 arguments 时怎样接收可变参数? 使用剩余参数 (...args),它是真数组,作用域和参数来源也更明确。

八、加强记忆

箭头函数可以记成“短语法 + 词法 this”。它适合回调,不适合构造器;适合继承外层 this,不适合需要调用者决定 this 的方法。

判断口诀可以进一步落成决策:需要动态 this 或构造能力时用普通函数,需要捕获外层 this 的短回调时再考虑箭头函数。