js 对象创建有哪几种方式

说明: 以下知识来源网上素材,纯属个人笔记; 如需了解可以查找原文,请勿在此纠结

在js中,对象是键值对的集合,可以通过很多种方式创建; 六种创建方式:对象字面量、构造函数、Object.create()、工厂函数、class、单例模式。

1.对象字面量(Object Literal)

用法: 直接通过{}定义对象,是最简单的方式;

原理: 直接分配内存创建一个普通对象,继承object.prototype;

  • 直接内存分配: 当使用{}定义对象时,js引擎会直接在堆内存中分配一个普通对象。
  • 隐藏原型继承: 该对象的[[Prototype]](即 proto) 会自动指向 Object.prototype, 继承原始对象默认方法 (如:toString).
  • 属性初始化: 字面量中的属性和方法会直接挂载到对象自身,而非原型链。

例子:

js 复制代码
const person {
    name: '小明',
    age: 25,
    greet() {
        console.log(`hi , i'm ${this.name}`)
    }
}
person.greet() //hi ,i'm 小明
js 复制代码
const obj = {key:"value"};

//等价于:
const obj = new Object(); //隐式调用 Object 构造函数
obj.key = "value";

特点:

  • 适合创建单例对象或一次性对象;
  • 所有属性方法均为实例自身成员,无法共享

2.构造函数(constructor function)

用法:通过 new 关键字调用构造函数创建对象

原理: new 操作

  • 1.创建空对象: 在内存中创建一个新对象 {}
  • 2.绑定原型:将新对象的[[Prototype]] 即原型链, 指向构造函数的prototype属性
  • 3.执行构造函数:将构造函数内的this指向新对象,执行构造函数代码(初始化属性)
  • 4.返回对象: 若构造函数未显示返回其他对象,则返回新对象;

例子:

js 复制代码
function person(name, age){
    // this = {};  (隐式操作)
    // this.__proto__ = person.prototype; (隐式操作)
    this.name = name;
    this.age = age;
    this.greet = function(){
        console.log(`hi, i'm ${this.name}`)
    }
    
    // return this;  (隐式操作)
}

const xiaoming = new person('小明', 25);
xiaoming.greet(); //hi, i'm 小明


//原型链结构: xiaoming.__proto__ -> person.prototype -> Object.prototype -> null;

缺点:每个实例的方法都是独立的,浪费内存(可以优化共享原型方法);

  • 若方法定义在构造函数内部,每个实例会有独立的方法副本(浪费内存);
  • 若方法定义在person.prototype上,所有实例共享同一方法(推荐做法)

3. Object.create()

用法:基于现有对象作为原型创建新对象。

原理:创建一个新对象,并将其Prototype 指向传入的对象;

  • 显式原型继承:直接创建一个新对象,并手动指定其[[Prototype]] 即:原型链 __ proto __
  • 参数处理: 1.若传入null, 新对象的[[Prototype]]为null (无原型链); 2.若传入对象proto, 新对象继承proto的属性和方法;

例子:

js 复制代码
const prototypeObj = {
    greet(){
         console.log(`hi, i'm ${this.name}`)
    }
}
const person = Object.create(prototypeObj);
person.name = "小明";
person.age = 10;
person.greet(); //hi , i'm 小明

扩展:可创建无原型的对象(Object.create(null)),适合纯粹的数据存储;

4.工厂函数(Factory Function)

用法: 封装对象创建逻辑的函数,直接返回新对象;

原理:手动创建对象并返回,不依赖 new 或原型链;

  • 封装对象创建: 通过普通函数返回新对象,不依赖new或者原型链。
  • 独立实例: 每次调用工厂函数都会产生新的对象,所有属性和方法均为实例自身成员。

例子:

js 复制代码
function createPeason(name,age){
    const obj = {}; //显示创建对象
    obj.name = name;
    obj.age = age;
    obj.greet = function(){}   //方法不共享
    return obj;
}
const xiaoming = createPeason('小明',10);
xiaoming.greet();  //hi, i'm 小明;

特点:避免 new 的使用,但方法无法共享(每个实例的方法独立)。

对比构造函数:

  • 优势: 更直观,避免new 的依赖。
  • 劣势: 方法无法共享,内存效率低。 (因为是闭包啊)

5.ES6 class 语法

用法:使用clase关键字定义类,通过new实例化;

原理:本质是构造函数的语法糖(构造函数另一种写法),基于原型链实现继承。

  • 方法挂载: 类中定义的方法会自动添加到prototype对象上,实现共享;
  • 继承机制: extends 关键字通过修改原型链实现继承(子类的prototype 指向父类实例)

例子:

js 复制代码
class Person {
    construtor(name,age){
        this.name = name;
        this.age = age;
    }
    greet(){
        console.log(`hi, i'm ${this.name}`)
    }
}
const xiaoming = new Person('小明',10);
xiaoming.greet(); // hi, i'm 小明;

//原型链结构: xiaoming.__proto__ -> Person.prototype -> Object.prototyle -> null;

优点: 语法更清晰,支持继承(extends)和静态方法(static)

6.单例模式(Singleton)

用法:确保一个类只有一个实例;

原理:通过闭包或模块化限制实例化次数

  • 闭包封装: 通过立即执行函数(iife)和闭包保存唯一实例的引用。
  • 惰性初始化: 在首次调用时创建实例,后续调用直接返回已存在的实例;

例子:

js 复制代码
const singleton - (function(){
    let instance;
    function createInstance() {
        return { id: Math.random() };
    }
    return {
        getInstance(){
            if(!instance) instance = createInstance();
            return instance;
        }
    }
})();

const obj1 = singleton.getInstance();
const obj2 = singleton.getInstance();
console.log(obj1 === obj2); //true

汇总 - 总结对比

方式 特点 适用场景
对象字面量 简单直接,适合一次性对象 简单数据存储、配置项
构造函数 可复用,但方法定义在原型上 节省内存 需要多个相似实例
Object.create() 灵活控制原型链,可创建无原型的对象 原型继承、纯净对象
工厂函数 避免 new, 但方法无法共享 简单对象生活
class 语法清晰,支持继承 面向对象开发
单例模式 全局唯一实例 全局状态管理

选择建议:

  • 简单对象: 优先用对象字面量或者工厂函数。
  • 复用和继承: 使用class或构造函数。
  • 原型控制: 使用Object.create()。
  • 全局唯一: 单例模式。

温馨说明: 以上素材来源网上,如有整理不对地方,欢迎指出

相关推荐
聪明的墨菲特i19 分钟前
React与Vue:哪个框架更适合入门?
开发语言·前端·javascript·vue.js·react.js
时光少年21 分钟前
Android 副屏录制方案
android·前端
拉不动的猪27 分钟前
v2升级v3需要兼顾的几个方面
前端·javascript·面试
时光少年30 分钟前
Android 局域网NIO案例实践
android·前端
半兽先生1 小时前
VueDOMPurifyHTML 防止 XSS(跨站脚本攻击) 风险
前端·xss
冴羽1 小时前
SvelteKit 最新中文文档教程(20)—— 最佳实践之性能
前端·javascript·svelte
Jackson__1 小时前
面试官:谈一下在 ts 中你对 any 和 unknow 的理解
前端·typescript
zpjing~.~1 小时前
css 二维码始终显示在按钮的正下方,并且根据不同的屏幕分辨率自动调整位置
前端·javascript·html
红虾程序员1 小时前
Linux进阶命令
linux·服务器·前端
yinuo1 小时前
uniapp在微信小程序中实现 SSE 流式响应
前端