Skip to content

JavaScript 函数的几种写法

函数声明与函数表达式

函数声明会被提升(hoisting),可以在声明之前调用:

javascript
function getUserName() {
  console.log('fetching user name...');
}
getUserName();

函数表达式将函数赋值给变量,只有变量声明被提升,赋值不会——在赋值前调用会报错:

javascript
const getUserInfo = function () {
  console.log('fetching user info...');
};
getUserInfo();

函数表达式可以是匿名的,也可以具名。具名函数表达式在调试时堆栈信息更清晰,且函数内部可以通过自身名字递归调用:

javascript
const calculate = function factorial(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
};

箭头函数

箭头函数是 ES6 引入的简写形式,核心差异在于不绑定自己的 thisargumentssupernew.target

javascript
const formatPrice = (price) => {
  return '¥' + price.toFixed(2);
};

箭头函数适合作为回调或需要继承外层 this 的场景——比如在 setTimeout 或事件处理中访问组件实例。但不要在需要动态 this 的场景使用它(比如作为对象方法时访问对象其他属性)。

立即执行函数(IIFE)

IIFE 的核心价值是创建独立作用域,避免变量污染:

javascript
(function () {
  const moduleState = { loaded: false };
  console.log('module initialized');
})();

(() => {
  console.log('arrow IIFE');
})();

在 ES6 模块化普及之前,IIFE 是实现模块隔离的常用手段。现在大多数场景已被 import/export 替代,但在某些需要立即执行且不暴露内部状态的初始化代码中仍然适用。

对象方法的几种写法

javascript
const orderService = {
  // 方法简写(ES6,推荐)
  createOrder() {
    console.log('Order created');
  },

  // 传统 function 表达式
  cancelOrder: function () {
    console.log('Order cancelled');
  },

  // 箭头函数——this 指向外层,不指向 orderService
  queryOrder: () => {
    console.log('Querying order');
  }
};

方法简写是对象中定义函数的推荐方式,语法简洁且语义明确。箭头函数作为对象方法时要特别注意:它的 this 不会指向对象本身,而是捕获定义时的外层 this

class 中的方法

javascript
class OrderManager {
  constructor(orderId) {
    this.orderId = orderId;
    // 构造函数中的实例方法
    this.printId = function () {
      console.log('Order ID:', this.orderId);
    };
  }

  // 原型方法,实例共享
  ship() {
    console.log('Shipping order', this.orderId);
  }

  // 静态方法
  static validate(orderData) {
    return orderData.items && orderData.items.length > 0;
  }
}

// 继承
class ExpressOrder extends OrderManager {
  constructor(orderId, trackingNumber) {
    super(orderId);
    this.trackingNumber = trackingNumber;
  }

  ship() {
    super.ship();
    console.log('Tracking:', this.trackingNumber);
  }
}

constructor 中定义的实例方法每个实例各自持有一份(不共享内存),原型方法所有实例共享一份,静态方法挂在类本身上与实例无关。面向具体实例数据的逻辑放原型方法,工具型的通用逻辑放静态方法。