箭头函数 vs 普通函数:JavaScript 核心差异全解析(含实战场景)
箭头函数是 ES6 引入的 JavaScript 语法糖,核心价值是简化代码并解决传统普通函数的this绑定痛点。二者在语法结构、this指向、功能特性和使用场景上存在本质区别,本文将从基础到进阶,结合实例全方位拆解差异,帮你精准掌握两种函数的选型逻辑。
一、语法差异:从冗余到精简的优化
语法设计是二者最直观的区别,箭头函数通过省略不必要的关键字,让代码更简洁聚焦。
普通函数:完整声明,兼容性强
普通函数支持两种定义方式,语法结构固定,需明确使用function关键字:
- 函数声明:
function 函数名(参数) { 函数体 },支持函数提升(可在定义前调用)。 - 函数表达式:
const 变量名 = function(参数) { 函数体 },无函数提升,需先定义后调用。
示例:
javascript
运行
// 函数声明(支持提升)
function calculateSum(a, b) {
return a + b;
}
// 函数表达式(无提升)
const calculateProduct = function(a, b) {
return a * b;
};
箭头函数:语法糖简化,场景化省略
箭头函数仅支持表达式定义(需赋值给变量),用=>替代function,且可根据场景省略语法元素:
- 单参数可省略括号:
const double = num => num * 2 - 单行表达式可省略花括号和
return:const add = (a, b) => a + b - 无参数需写空括号:
const getNow = () => new Date() - 多行函数体需保留花括号和
return:const formatStr = str => { const newStr = str.trim(); return newStr.toUpperCase(); }
示例对比:
javascript
运行
// 普通函数
function filterEven(arr) {
return arr.filter(function(item) {
return item % 2 === 0;
});
}
// 箭头函数(嵌套简化)
const filterEven = arr => arr.filter(item => item % 2 === 0);
二、核心区别:this 指向机制(最关键差异)
this的绑定规则是两种函数的核心分歧,直接决定了它们的适用场景。
普通函数:动态绑定,指向调用者
普通函数的this在调用时 确定,指向触发函数执行的 "调用者",且可通过call、apply、bind手动修改:
- 全局调用(非严格模式):
this指向全局对象(浏览器为window,Node.js 为global)。 - 作为对象方法调用:
this指向该对象。 - 构造函数调用(
new关键字):this指向新创建的实例。 - 事件绑定调用:
this指向绑定事件的 DOM 元素。
示例:
javascript
运行
const user = {
name: "张三",
sayName: function() {
console.log(this.name); // 指向user对象,输出"张三"
}
};
function showThis() {
console.log(this);
}
showThis(); // 全局调用,输出window(浏览器环境)
showThis.call(user); // 手动绑定,输出user对象
箭头函数:静态绑定,继承外层作用域
箭头函数没有自己的this ,其this在定义时 就已确定,直接继承外层作用域的this,且后续无法修改:
- 无论通过何种方式调用,
this都不会改变。 - 不存在 "调用者绑定""构造函数绑定" 等规则。
- 无法通过
call、apply、bind修改this指向(传入的第一个参数会被忽略)。
示例:
javascript
运行
const user = {
name: "张三",
sayName: () => {
console.log(this.name); // 继承全局this,输出undefined(浏览器环境)
},
asyncSayName: function() {
setTimeout(() => {
console.log(this.name); // 继承asyncSayName的this(user对象),输出"张三"
}, 1000);
}
};
user.sayName(); // 输出undefined
user.asyncSayName(); // 输出"张三"
三、功能特性:构造能力与原型差异
两种函数在实例创建、原型属性等功能上的差异,进一步明确了它们的使用边界。
普通函数:支持构造实例,拥有原型
普通函数可作为构造函数使用,通过new关键字创建对象实例,且自带prototype属性(支持原型继承):
javascript
运行
// 普通函数作为构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// 原型上添加方法(所有实例共享)
Person.prototype.sayInfo = function() {
console.log(`${this.name},${this.age}岁`);
};
const person1 = new Person("李四", 25);
person1.sayInfo(); // 输出"李四,25岁"
console.log(Person.prototype); // 存在原型对象
箭头函数:不可构造,无原型属性
箭头函数因缺少自身this和prototype属性,无法作为构造函数使用:
- 用
new调用箭头函数会抛出TypeError。 - 箭头函数的
prototype属性为undefined,无法实现原型继承。
示例:
javascript
运行
const Person = (name, age) => {
this.name = name; // 无效,this指向外层作用域
};
// 报错:Person is not a constructor
const person2 = new Person("王五", 30);
console.log(Person.prototype); // 输出undefined
四、补充差异:arguments 与绑定方法
除核心特性外,二者在参数获取、特殊方法支持上还有细节区别:
arguments 对象
- 普通函数:支持
arguments对象,可获取所有传入参数(类数组形式)。 - 箭头函数:无
arguments对象,需通过 "剩余参数"(...args)获取参数。
示例:
javascript
运行
// 普通函数:使用arguments
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(sum(1, 2, 3)); // 输出6
// 箭头函数:使用剩余参数
const sumArrow = (...args) => {
return args.reduce((total, curr) => total + curr, 0);
};
console.log(sumArrow(1, 2, 3, 4)); // 输出10
call/apply/bind 的作用
- 普通函数:这三个方法可修改
this指向,并执行或返回新函数。 - 箭头函数:这三个方法仅能传递参数,无法修改
this(this仍继承外层)。
示例:
javascript
运行
const obj1 = { value: 10 };
const obj2 = { value: 20 };
// 普通函数
function getValue() {
return this.value;
}
console.log(getValue.call(obj1)); // 输出10(this指向obj1)
// 箭头函数
const getValueArrow = () => this.value;
console.log(getValueArrow.call(obj2)); // 输出undefined(this仍指向全局)
五、实战选型:场景决定用法
两种函数无绝对优劣,需根据场景灵活选择:
优先使用箭头函数的场景
-
回调函数(数组遍历、定时器、Promise):避免
this丢失。javascript
运行
// 数组遍历 const arr = [1, 2, 3]; const doubled = arr.map(item => item * 2); // Promise回调 fetch("/api/data") .then(res => res.json()) .catch(err => console.error(err)); -
简单逻辑函数(纯计算、数据格式化):语法简洁,无需
this。javascript
运行
const formatDate = date => date.toLocaleDateString("zh-CN");
必须使用普通函数的场景
-
构造函数(创建实例):需
this绑定实例和原型继承。 -
对象方法:需通过
this访问对象自身属性。javascript
运行
const calculator = { num: 0, add: function(value) { this.num += value; // this指向calculator return this.num; } }; -
需使用
arguments或原型的场景:箭头函数不支持这些特性。
总结:核心差异速查表
| 对比维度 | 普通函数 | 箭头函数 |
|---|---|---|
| 语法结构 | 需function关键字,支持声明 / 表达式 |
用=>,仅支持表达式 |
this指向 |
调用时动态绑定(指向调用者) | 定义时静态绑定(继承外层) |
| 构造能力 | 可new调用,有prototype |
不可new,无prototype |
| arguments 对象 | 支持 | 不支持(用剩余参数替代) |
| 适用场景 | 构造函数、对象方法、复杂逻辑 | 回调函数、纯函数、简单逻辑 |
要不要我帮你整理一份箭头函数与普通函数差异对比表(Markdown 格式),方便你直接嵌入博客或打印参考?