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

箭头函数 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
  • 单行表达式可省略花括号和returnconst add = (a, b) => a + b
  • 无参数需写空括号:const getNow = () => new Date()
  • 多行函数体需保留花括号和returnconst 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调用时 确定,指向触发函数执行的 "调用者",且可通过callapplybind手动修改:

  • 全局调用(非严格模式):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都不会改变。
  • 不存在 "调用者绑定""构造函数绑定" 等规则。
  • 无法通过callapplybind修改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); // 存在原型对象

箭头函数:不可构造,无原型属性

箭头函数因缺少自身thisprototype属性,无法作为构造函数使用:

  • 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指向,并执行或返回新函数。
  • 箭头函数:这三个方法仅能传递参数,无法修改thisthis仍继承外层)。

示例:

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 格式),方便你直接嵌入博客或打印参考?

相关推荐
AI科技星1 小时前
张祥前统一场论:引力场与磁矢势的关联,反引力场生成及拉格朗日点解析(网友问题解答)
开发语言·数据结构·经验分享·线性代数·算法
β添砖java1 小时前
python第一阶段第八章文件操作
开发语言·python
-森屿安年-1 小时前
二叉平衡树的实现
开发语言·数据结构·c++
脑极体1 小时前
蓝河入海:Rust先行者vivo的开源之志
开发语言·后端·rust·开源
foxsen_xia1 小时前
go(基础01)——协程
开发语言·算法·golang
源代码•宸1 小时前
GoLang并发简单例子(goroutine + channel + WaitGroup)
开发语言·经验分享·后端·学习·golang
将心ONE1 小时前
pip导出项目依赖
开发语言·python·pip
A24207349301 小时前
js流程控制语句
开发语言·前端·javascript
kesifan1 小时前
JAVA的线程的周期及调度
java·开发语言