本文将详细探讨JavaScript中普通函数和箭头函数的定义方式,以及它们之间的关键性区别。通过深入比较这两种函数形式,读者可以更好地理解它们在编程中的应用场景和影响。

普通函数的定义

普通函数 是JavaScript中最传统和基本的函数定义方式,有多种声明形式。

1. 函数声明(Function Declaration)
function functionName(parameters) {
  // 函数体
  return value; // 可选
}
2. 函数表达式(Function Expression)
const functionName = function(parameters) {
  // 函数体
  return value; // 可选
};
3. 命名函数表达式(Named Function Expression)
const functionName = function internalName(parameters) {
  // 函数体
  return value; // 可选
};

箭头函数的定义

箭头函数(Arrow Function)是ES6(ECMAScript 2015)引入的函数表达式的简洁语法形式。

1. 基本语法
const functionName = (parameters) => {
  // 函数体
  return value; // 可选
};
2. 单行表达式(隐式返回)
const functionName = (parameters) => expression;
// 等同于带return的多行形式
3. 单个参数(省略括号)
const functionName = parameter => {
  // 函数体
};
4. 无参数
const functionName = () => {
  // 函数体
};

示例对比一

传统函数表达式 vs 箭头函数:

// 传统函数表达式
const add1 = function(a, b) {
  return a + b;
};

// 箭头函数
const add2 = (a, b) => a + b;

this 绑定示例:

function Person() {
  this.age = 0;
  
  // 传统函数中的 this 会根据调用方式变化
  setTimeout(function() {
    console.log(this.age); // 输出 undefined,因为 this 指向全局对象
  }, 1000);
  
  // 箭头函数继承外层作用域的 this
  setTimeout(() => {
    console.log(this.age); // 输出 0,因为 this 指向 Person 实例
  }, 1000);
}

const p = new Person();

两种函数的关键区别

1. this绑定

普通函数:this的值取决于函数的调用方式(运行时绑定)

  • 作为方法调用:this指向调用对象。

  • 作为函数调用:this指向全局对象或undefined(严格模式)。

  • 使用call/apply/bind:this指向指定对象。

  • 作为构造函数:this指向新创建的对象。

箭头函数:this 值在定义时确定(词法绑定)

  • 继承自定义它的外部作用域。

  • 无法通过call/apply/bind改变其 this 值。

2. 构造函数能力
  • 普通函数 :可以用作构造函数,使用 new 关键字。

  • 箭头函数 :不能用作构造函数,使用 new 会抛出TypeError。

3. arguments对象
  • 普通函数 :有自己的 arguments 对象,包含所有传入的参数。

  • 箭头函数 :没有自己的 arguments 对象,但可以访问外部函数的 arguments 。

4. 原型对象
  • 普通函数 :有原型对象(prototype)。

  • 箭头函数 :没有原型对象。

5. super关键字
  • 普通函数 :在类方法中可以使用 super 关键字。

  • 箭头函数 :不能使用 super 关键字。

6. yield关键字
  • 普通函数 :可以用作生成器函数(使用 yield )。

  • 箭头函数 :不能用作生成器函数。

示例对比二

this绑定示例
const obj = {
  value: 10,
  testArrow: function() {
    setTimeout(() => {
      console.log('箭头函数:', this.value); // 10
    }, 100);
  },
  testNormal: function() {
    setTimeout(function() {
      console.log('普通函数:', this.value); // undefined
    }, 100);
  }
};

obj.testArrow(); // 输出: 箭头函数: 10
obj.testNormal(); // 输出: 普通函数: undefined
构造函数示例
// 普通函数作为构造函数
function Person(name) {
  this.name = name;
}
const person = new Person('John'); // 正常工作

// 箭头函数不能作为构造函数
const PersonArrow = (name) => { this.name = name; };
// const personArrow = new PersonArrow('John'); // TypeError: PersonArrow is not a constructor

更深入的理解

箭头函数的this是词法作用域
const obj = {
  value: 10,
  method: function() {
    // 这里的this指向obj
    const arrow = () => {
      console.log(this.value); // 10 - 继承method的this
    };
    arrow();
  }
};
普通函数的this是动态绑定
const obj = {
  value: 10,
  method: function() {
    // 这里的this指向obj
    const normal = function() {
      console.log(this.value); // undefined - 取决于调用方式
    };
    normal(); // 直接调用,this为undefined(严格模式)
  }
};

适用场景

普通函数适合:
  • 需要动态 this 上下文的场景。

  • 作为构造函数创建对象。

  • 需要使用 arguments 对象的场景。

  • 需要定义生成器函数。

箭头函数适合:
  • 简短的回调函数。

  • 需要保持外部作用域 this 的场景。

  • 数组方法的回调(如map、filter、forEach)。

  • 不需要自己的 this 、 arguments 、super 或 new.target 的函数。

总结

特性

箭头函数

普通函数

this绑定

继承外层作用域

动态绑定

绑定时机

定义时

调用时

可改变

不可改变

可通过call/apply/bind改变

在setTimeout中

保持外层this

指向window/undefined