You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

何时应使用JavaScript构造函数?对比普通函数的适用场景

关于构造函数与普通工厂函数的使用场景疑问

我自己一直以来从没使用过类或构造函数,好奇有没有必须使用它们的场景。下面两段代码功能基本一致,一段用构造函数实现,另一段用普通函数实现:

使用构造函数的实现

function Food(foodName, foodPrice) {
   Currencies.call(this, foodPrice);
   this.category = 'food';
   this.name = foodName;
}

function Currencies(usd) {
   this.usd = usd;
   this.won = +usd * 1000;
}

const pizza = new Food('pizza', 30); // { usd: 30, won: 30000, category: 'food', name: 'pizza' }
const burger = new Food('burger', 10); // { usd: 10, won: 10000, category: 'food', name: 'burger' }

不使用构造函数的实现(普通工厂函数)

function food(foodName, foodPrice) {
   return { name: foodName, category: 'food', ...(currencies(foodPrice)) }
}

function currencies(usd) {
   return { usd, won: usd * 1000 }
}

const pizza = food('pizza', 30); // { usd: 30, won: 30000, category: 'food', name: 'pizza' }
const burger = food('burger', 10); // { usd: 10, won: 10000, category: 'food', name: 'burger' }

我感觉不使用构造函数的写法更简洁,所以平时会尽量避免用构造函数。想问问大家的偏好和原因,以及什么时候会选择用构造函数而非普通函数?


回答

首先得说,工厂函数(你写的普通函数)在简单场景下确实更清爽,很多开发者都会优先用,但构造函数(包括ES6的class,本质是构造函数的语法糖)在不少场景下是不可替代或者更合适的:

1. 方法复用,节省内存

如果你的对象需要共享方法,构造函数的优势就体现出来了。比如给Food加一个计算总价的方法:

// 构造函数写法:方法放在原型上,所有实例共享
Food.prototype.calculateTotal = function(taxRate) {
  return this.usd * (1 + taxRate);
};
// 所有Food实例都用同一个方法,内存只占用一份

而如果用工厂函数,每次调用都要重新创建方法:

function food(foodName, foodPrice) {
  return {
    name: foodName,
    category: 'food',
    ...currencies(foodPrice),
    calculateTotal: function(taxRate) { // 每个对象都生成一个新函数,浪费内存
      return this.usd * (1 + taxRate);
    }
  }
}

虽然可以把方法抽出来单独定义,但这样就破坏了工厂函数的封装性,不如构造函数的原型链方式自然。

2. 类型识别与区分

用构造函数创建的实例可以通过instanceof判断类型:

console.log(pizza instanceof Food); // true

但工厂函数返回的都是普通Object,没法区分它是Food还是别的什么对象:

console.log(pizza instanceof Object); // true
console.log(pizza instanceof food); // false,因为food不是构造函数

如果你的代码需要判断对象的具体类型(比如在函数里做类型校验),构造函数是更可靠的选择。

3. 复杂继承场景

当你需要实现类之间的继承时,构造函数配合原型链的方式更成熟、更易维护。比如想让Drink类继承Currencies,同时扩展自己的属性:

function Drink(drinkName, drinkPrice) {
  Currencies.call(this, drinkPrice);
  this.category = 'drink';
  this.name = drinkName;
}
// 继承原型方法
Drink.prototype = Object.create(Currencies.prototype);
Drink.prototype.constructor = Drink;

而用工厂函数实现继承,需要手动合并对象、处理属性覆盖,复杂场景下很容易出问题,代码也会变得臃肿。

4. 真正的封装(ES6+场景)

ES6的class是构造函数的语法糖,它支持私有字段(#开头的字段),这些字段只能在类内部访问,外部无法修改,实现了真正的封装:

class Food {
  #taxRate = 0.08;
  constructor(foodName, foodPrice) {
    this.usd = foodPrice;
    this.won = foodPrice * 1000;
    this.category = 'food';
    this.name = foodName;
  }
  calculateTotal() {
    return this.usd * (1 + this.#taxRate);
  }
}

而工厂函数返回的对象,所有属性都是公开的,没法做到这种严格的封装。

关于偏好

  • 简单场景(比如只创建几个属性单一的对象):优先用工厂函数,代码简洁,不用考虑new关键字和原型链。
  • 复杂场景(需要方法复用、类型识别、继承、封装):用构造函数或ES6 class,代码结构更清晰,可维护性更高。

内容的提问来源于stack exchange,提问作者passionateLearner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 09:01:08