[JS Daily] ES6 箭头函数 vs 普通函数 - 看似简单,坑在细节

ES6 箭头函数 vs 普通函数 - 看似简单,坑在细节

2026-04-03 · JavaScript 深度解析

箭头函数是 ES6 最受欢迎的特性之一。写法简洁,一行代码搞定回调,谁不爱?但很多人只看到了"写法更短"这个表面优势,却在实际项目中踩了 this 的坑。今天我们彻底搞清楚箭头函数和普通函数到底有什么不同。

一、语法对比:写法差异

普通函数的几种写法:

// 函数声明
function add(a, b) {
return a + b;
}
// 函数表达式
const add = function(a, b) {
return a + b;
};

箭头函数的等价写法:

const add = (a, b) => {
return a + b;
};
// 单行可省略大括号和 return
const add = (a, b) => a + b;
// 单参数可省略括号
const double = x => x * 2;

💡 写法更短的本质

箭头函数不是"语法糖",它有本质的行为差异。短只是表象,this 绑定才是关键。

二、核心差异:this 绑定

这是箭头函数和普通函数最大的区别,也是最容易踩坑的地方。

普通函数的 this:谁调用,this 就是谁

const obj = {
name: 'Alice',
greet: function() {
console.log(`Hello, ${this.name}`);
}
};
obj.greet(); // Hello, Alice
// 但如果这样呢?
const fn = obj.greet;
fn(); // Hello, undefined (this 丢失)

普通函数的 this运行时动态绑定的,取决于调用方式。你把它赋值给变量后单独调用,this 就变成了 undefined(严格模式)或 window(非严格模式)。

箭头函数的 this:定义时就确定,永远不会变

const obj = {
name: 'Alice',
greet: () => {
console.log(`Hello, ${this.name}`);
}
};
obj.greet(); // Hello, undefined

等等,为什么还是 undefined?因为箭头函数没有自己的 this,它从定义时的外层作用域继承 this。这里外层是全局作用域,this 自然是 undefined

⚠️ 常见错误:对象方法不要用箭头函数

箭头函数作为对象方法时,this 不会指向对象本身。需要访问对象属性时,请使用普通函数。

三、箭头函数的正确使用场景

✅ 场景 1:回调函数(保留外层 this)

class Counter {
constructor() {
this.count = 0;
}
// ✅ 箭头函数:自动绑定外层 this
start() {
setInterval(() => {
this.count++;
console.log(this.count);
}, 1000);
}
// ❌ 普通函数:需要手动 bind
startOld() {
setInterval(function() {
this.count++; // TypeError: this is undefined
}.bind(this), 1000); // 需要 bind 才行
}
}

✅ 场景 2:数组方法的简洁写法

const numbers = [1, 2, 3, 4, 5];
// 普通函数写法
const doubled1 = numbers.map(function(n) {
return n * 2;
});
// 箭头函数写法
const doubled2 = numbers.map(n => n * 2);
// 链式调用更清晰
const result = numbers
.filter(n => n > 2)
.map(n => n * 10)
.reduce((sum, n) => sum + n, 0);
console.log(result); // 70

✅ 场景 3:Promise 链式调用

fetch('/api/users')
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));

四、箭头函数的限制

箭头函数不是万能的,以下场景不能使用

限制 原因
不能作为构造函数 没有 [[Construct]] 内部方法,不能 new
没有 arguments 对象 需要用 ...args 剩余参数替代
没有 prototype 没有原型链,不能用作基类
不能用作生成器 yield 只能在普通函数中使用
不适合 DOM 事件处理器 事件处理器中的 this 应指向触发元素

五、实战案例:正确选择函数类型

// ❌ 错误:React 类组件中用箭头函数定义方法
class BadComponent extends React.Component {
// 这会导致每次渲染都创建新函数
handleClick = () => { /* ... */ };
}
// ✅ 正确:普通方法 + 箭头回调
class GoodComponent extends React.Component {
handleClick() { /* ... */ }
render() {
return <button onClick={() => this.handleClick()}>;
}
}

六、速查对比表

特性 箭头函数 普通函数
this 绑定 词法作用域(定义时确定) 动态绑定(调用时确定)
arguments ❌ 没有 ✅ 有
prototype ❌ 没有 ✅ 有
可作构造函数 ❌ 不能 new ✅ 可以 new
call/apply/bind ❌ 不能改变 this ✅ 可以改变
yield ❌ 不能用 ✅ 可以用

七、最佳实践总结

✅ 箭头函数适用场景

  • 数组方法回调(map、filter、reduce、forEach)
  • Promise 链式调用(then、catch、finally)
  • 事件处理器中需要访问外层 this 的场景
  • 简单的纯函数运算

❌ 不要用箭头函数的场景

  • 对象方法(需要访问对象自身的属性)
  • 原型方法(需要访问实例)
  • 构造函数
  • DOM 事件处理器(需要访问 event.target)
  • 生成器函数

小结

箭头函数的本质不是"写法更短",而是 this 的词法绑定。理解这一点,你就能在合适的场景用好它:

  • 需要保留外层 this → 箭头函数
  • 需要动态 this 或构造函数 → 普通函数
  • 不确定时,先问自己:this 应该指向谁?

下次写 function 还是 => 时,停下来想一想这个函数需不需要自己的 this。


#JavaScript #ES6 #箭头函数 #教程

评论

此博客中的热门博文

OpenClaw 救援机器人建设与演进全记录 - 从单点故障到双实例自愈体系

Lossless Claw:无损上下文管理插件分析报告

[Hello-Agents] Day 2: 第一章 初识智能体