【js篇】JavaScript 对象创建的 6 种方式:从基础到高级

在 JavaScript 中,对象是核心数据类型之一。由于其动态性和灵活性,创建对象的方式多种多样。每种方式都有其适用场景和局限性。

本文将系统梳理 6 种对象创建方式,深入剖析其原理、优缺点,并提供代码示例。


一、字面量创建(Object Literal)

✅ 基础用法

js 复制代码
const person = {
  name: 'Alice',
  age: 25,
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

✅ 优点

  • 语法简洁,可读性强;
  • 适合创建单个对象

❌ 缺点

  • 创建大量相似对象时,代码重复严重;
  • 无法复用。
js 复制代码
// 重复代码!
const person1 = { name: 'Alice', age: 25 };
const person2 = { name: 'Bob', age: 30 };
const person3 = { name: 'Charlie', age: 35 };

适用场景:配置对象、单例、临时数据结构。


二、工厂模式(Factory Pattern)

✅ 核心思想:用函数封装创建细节

js 复制代码
function createPerson(name, age) {
  return {
    name,
    age,
    greet() {
      console.log(`Hello, I'm ${this.name}`);
    }
  };
}

const p1 = createPerson('Alice', 25);
const p2 = createPerson('Bob', 30);

✅ 优点

  • 解决了代码重复问题;
  • 可通过参数初始化对象。

❌ 缺点

  • 无法识别对象类型

    js 复制代码
    console.log(p1 instanceof createPerson); // ❌ false
    console.log(typeof p1); // "object" --- 无法区分具体类型
  • 所有方法都在每个实例中重新创建,浪费内存。

适用场景:需要创建多种类型对象的工厂函数。


三、构造函数模式(Constructor Pattern)

✅ 核心:使用 new 关键字

js 复制代码
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.greet = function() {
    console.log(`Hello, I'm ${this.name}`);
  };
}

const p1 = new Person('Alice', 25);
const p2 = new Person('Bob', 30);

new 的执行过程

  1. 创建一个新对象;
  2. 将构造函数的 prototype 赋值给新对象的 [[Prototype]]
  3. this 指向新对象;
  4. 执行构造函数体;
  5. 如果函数没有返回对象,则返回新对象。

✅ 优点

  • 可通过 instanceof 识别类型:

    js 复制代码
    console.log(p1 instanceof Person); // ✅ true
  • 支持参数初始化。

❌ 缺点

  • 方法在每个实例中重复创建 ,浪费内存:

    js 复制代码
    console.log(p1.greet === p2.greet); // ❌ false

适用场景:需要类型识别的简单对象创建。


四、原型模式(Prototype Pattern)

✅ 核心:共享 prototype 上的属性和方法

js 复制代码
function Person() {}
Person.prototype.name = 'Unknown';
Person.prototype.age = 0;
Person.prototype.greet = function() {
  console.log(`Hello, I'm ${this.name}`);
};

const p1 = new Person();
p1.name = 'Alice';
p1.age = 25;

const p2 = new Person();
p2.name = 'Bob';
p2.age = 30;

✅ 优点

  • 方法只在原型上创建一次,内存高效

    js 复制代码
    console.log(p1.greet === p2.greet); // ✅ true

❌ 缺点

  • 无法通过构造函数传参初始化

  • 引用类型属性被所有实例共享

    js 复制代码
    Person.prototype.hobbies = ['reading'];
    
    p1.hobbies.push('coding');
    console.log(p2.hobbies); // ['reading', 'coding'] --- 被污染!

适用场景:方法共享,但不适合存储实例数据。


五、组合模式(构造函数 + 原型)------ 最佳实践

✅ 核心:属性在构造函数中定义,方法在原型上定义

js 复制代码
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.hobbies = []; // 每个实例独有
}

Person.prototype.greet = function() {
  console.log(`Hello, I'm ${this.name}`);
};

const p1 = new Person('Alice', 25);
const p2 = new Person('Bob', 30);

p1.hobbies.push('reading');
p2.hobbies.push('coding');

console.log(p1.hobbies); // ['reading']
console.log(p2.hobbies); // ['coding'] --- 互不影响

✅ 优点

  • ✅ 属性私有,避免共享问题;
  • ✅ 方法共享,节省内存;
  • ✅ 支持类型识别;
  • ✅ 支持参数初始化。

❌ 缺点

  • 代码分散在构造函数和原型中,封装性差

适用场景 :ES6 之前的标准对象创建方式


六、动态原型模式(Dynamic Prototype Pattern)

✅ 核心:在构造函数内部初始化原型,仅一次

js 复制代码
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.hobbies = [];

  // 仅在第一次调用时初始化原型
  if (typeof this.greet !== 'function') {
    Person.prototype.greet = function() {
      console.log(`Hello, I'm ${this.name}`);
    };
  }
}

const p1 = new Person('Alice', 25);
const p2 = new Person('Bob', 30);

✅ 优点

  • 封装了组合模式的逻辑;
  • 方法只创建一次;
  • 支持类型识别。

❌ 缺点

  • 破坏了构造函数和原型的"分离"原则;
  • 代码可读性略差。

适用场景:希望完全封装对象创建逻辑。


七、寄生构造函数模式(Parasitic Constructor Pattern)

✅ 核心:扩展已有类型,不修改原构造函数

js 复制代码
function SpecialArray() {
  const arr = new Array();
  
  // 扩展功能
  arr.first = function() {
    return this[0];
  };
  
  arr.last = function() {
    return this[this.length - 1];
  };
  
  // 参数处理
  for (let i = 0; i < arguments.length; i++) {
    arr.push(arguments[i]);
  }
  
  return arr;
}

const special = new SpecialArray(1, 2, 3);
console.log(special.first()); // 1
console.log(special.last());  // 3

✅ 优点

  • 可以基于原生类型(如 Array、Date)进行扩展;
  • 不污染原构造函数。

❌ 缺点

  • 无法通过 instanceof 识别类型:

    js 复制代码
    console.log(special instanceof SpecialArray); // ❌ false
  • 本质上还是工厂模式。

适用场景:需要扩展原生对象但不修改其原型。


八、ES6 Class(现代方式)

js 复制代码
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
    this.hobbies = [];
  }

  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
}

const p1 = new Person('Alice', 25);

本质class 是上述组合模式的语法糖,但更清晰、更安全。


九、总结:选择哪种方式?

方式 类型识别 内存效率 初始化 封装性 推荐度
字面量 ⚠️ ⭐⭐
工厂模式 ⭐⭐⭐
构造函数 ⭐⭐⭐
原型模式 ⚠️ ⭐⭐
组合模式 ⚠️ ⭐⭐⭐⭐⭐
动态原型 ⭐⭐⭐⭐
寄生构造 ⭐⭐⭐

最终建议

  • 现代开发 :使用 class
  • ES5 环境 :使用组合模式
  • 特殊需求:根据场景选择工厂、寄生等模式。

💡 结语

"理解对象创建方式,是掌握 JavaScript 面向对象编程的基石。"

从字面量到 class,JavaScript 的对象创建方式不断演进,核心目标始终是:

  • 代码复用
  • 内存优化
  • 类型识别
  • 开发效率

掌握这些模式,你就能写出更健壮、更可维护的代码。

相关推荐
wayne2142 小时前
跨平台开发框架全景分析:Flutter、RN、KMM 与腾讯 Kuikly 谁更值得选择?
前端
LuckySusu2 小时前
【js篇】async/await 的五大核心优势:让异步代码像同步一样清晰
前端·javascript
艾雅法拉拉2 小时前
JS知识点回顾(1)
前端·javascript·面试
LuckySusu2 小时前
【js篇】Promise 解决了什么问题?—— 彻底告别“回调地狱”
前端·javascript
程序员海军2 小时前
如何让AI真正理解你的需求
前端·后端·aigc
passer9812 小时前
基于Vue的场景解决
前端·vue.js
用户458203153172 小时前
CSS过渡(Transition)详解:创建平滑状态变化
前端·css
春秋半夏2 小时前
本地项目一键开启 HTTPS(mkcert + Vite / Vue 配置教程)
前端
穿花云烛展2 小时前
实习日记2(与form表单的爱恨情仇1)
前端