人人都会AI编程

9.5 箭头函数:语法特性、与普通函数的核心差异

更新时间:2026-07-11

箭头函数是 ES6(ES2015)引入的一种新的函数定义方式。它不仅仅是写法上的简化,更在 this 绑定、arguments 对象等核心行为上与普通函数存在本质区别。理解这些差异,是写出可预测、无 Bug 的 JavaScript 代码的关键。

9.5.1 箭头函数的基本语法

箭头函数的语法非常简洁,根据参数数量和函数体复杂度,可以有不同的简写形式:

// 无参数:必须写一对空括号
const sayHello = () => console.log('Hello');

// 单个参数:可以省略括号
const double = x => x * 2;

// 多个参数:必须用括号包裹
const add = (a, b) => a + b;

// 函数体多行:需要用大括号,并显式 return
const sum = (a, b) => {
  const result = a + b;
  return result;
};

// 直接返回对象字面量:需要用小括号包裹对象
const createUser = (name, age) => ({ name, age });

箭头函数让匿名回调的书写变得极为清爽,尤其在数组操作中:

const numbers = [1, 2, 3, 4];
const doubled = numbers.map(n => n * 2);  // [2, 4, 6, 8]
const evens = numbers.filter(n => n % 2 === 0); // [2, 4]

9.5.2 与普通函数的核心差异

虽然箭头函数看起来只是普通函数的“简写版”,但它在四个关键行为上有根本不同。

差异一:没有自己的 this

普通函数的 this 是动态绑定的,取决于调用方式。箭头函数没有自己的 this,它会捕获定义时所在上下文的 this 值,这个值在整个生命周期中不会改变。这就是所谓的“词法 this”。

// 普通函数:this 取决于调用方式
const obj1 = {
  name: 'Alice',
  greet: function() {
    console.log(this.name);
  }
};
obj1.greet(); // 'Alice',this 指向 obj1

const greetFn = obj1.greet;
greetFn(); // undefined(非严格模式下指向 window,严格模式下 undefined)

// 箭头函数:this 继承自定义时的外层作用域
const obj2 = {
  name: 'Bob',
  greet: () => {
    console.log(this.name);
  }
};
obj2.greet(); // undefined,因为定义时外层 this 不是 obj2(可能是 window/global)

典型应用场景:在回调函数中保留外层的 this

class Timer {
  constructor() {
    this.seconds = 0;
    // 普通函数需要 bind,箭头函数直接使用外层 this
    setInterval(() => {
      this.seconds++;   // this 指向 Timer 实例
    }, 1000);
  }
}

使用普通函数时,setInterval(function(){...}) 中的 this 会丢失指向,而箭头函数天然绑定定义时的 this,这也是它在前端框架(如 React 类组件)中广受欢迎的原因。

差异二:没有 arguments 对象

普通函数内部可以使用 arguments 对象访问所有传入的实参。箭头函数没有自己的 arguments,如果在其中使用 arguments,会引用外层作用域的 arguments,这通常不是期望的行为。

function outer() {
  // 普通函数
  const normal = function() {
    console.log(arguments);
  };
  normal(1, 2, 3); // [1, 2, 3]

  // 箭头函数
  const arrow = () => {
    console.log(arguments);
  };
  arrow(4, 5, 6); // 可能输出 outer 函数的 arguments
}
outer('a', 'b');

正确做法:使用剩余参数(rest parameter)代替。

const arrow = (...args) => {
  console.log(args); // [4, 5, 6]
};
arrow(4, 5, 6);

差异三:不能作为构造函数

箭头函数没有 [[Construct]] 内部方法,不能使用 new 调用。尝试对箭头函数使用 new 会抛出 TypeError

const Person = (name) => {
  this.name = name; // 这里的 this 是外层作用域的
};
// const p = new Person('Jack'); // 报错:Person is not a constructor

同时,箭头函数也没有 prototype 属性:

const fn = () => {};
console.log(fn.prototype); // undefined

这一特性决定了,如果需要创建可实例化的对象构造器,必须使用普通函数或 class

差异四:不能使用 yield

箭头函数不能用作生成器函数,即不能在函数体内使用 yield 关键字。如果需要定义生成器,必须使用 function* 语法。

// 普通生成器
function* gen() {
  yield 1;
}

// 箭头函数无法定义生成器
// const gen = *() => {};  // 语法错误

9.5.3 适用场景与避坑指南

推荐使用箭头函数的场景:

  • 简短的回调函数,尤其是数组方法、Promise 链、事件监听器需要绑定外层 this 时。
  • 函数体内不需要独立 thisarguments,且不希望被动态 this 所困扰的场合。

不推荐或应避免的场景:

  • 对象方法(尤其是需要访问当前对象的属性时),除非你明确想要绑定外层 this
  • 需要使用 arguments 对象时(用剩余参数替代)。
  • 需要作为构造函数的场景。
  • 需要函数动态上下文(如某些库通过函数上下文传入额外信息)。

结合对象方法的例子:

const counter = {
  count: 0,
  increment: () => {
    this.count++;  // 不生效,this 指向外层(可能是 window)
  }
};
counter.increment();
console.log(counter.count); // 仍然是 0,错误用法

正确写法应为普通函数方法或使用 ES6 方法简写:

const counter = {
  count: 0,
  increment() {
    this.count++;
  }
};

9.5.4 小结

箭头函数不只是 shorter syntax,更是一种行为有本质区别的函数类型。它在带来 this 确定性和简洁性的同时,也放弃了普通函数的部分能力。掌握这些差异,你就可以放心地在恰当的场景中让代码更清晰易读,同时避免因错误使用而导致的棘手 Bug。