您现在的位置是:网站首页 > 对象创建方式文章详情
对象创建方式
陈川
【
JavaScript
】
24088人已围观
4648字
在JavaScript中,对象是核心概念之一,创建对象的方式多种多样,每种方式都有其适用场景和优缺点。从简单的字面量到复杂的构造函数和类,开发者可以根据需求选择最合适的方法。
对象字面量
对象字面量是最简单直接的创建对象的方式,适合快速定义简单对象。语法简洁,直接通过{}
定义属性和方法。
const person = {
name: 'Alice',
age: 25,
greet() {
console.log(`Hello, my name is ${this.name}`);
}
};
person.greet(); // 输出: Hello, my name is Alice
这种方式适合不需要复用对象结构的场景,但如果需要创建多个相似对象,重复代码会增多。
工厂模式
工厂模式通过函数封装对象创建过程,解决字面量方式重复代码的问题。函数内部构造对象并返回。
function createPerson(name, age) {
return {
name,
age,
greet() {
console.log(`Hello, my name is ${this.name}`);
}
};
}
const person1 = createPerson('Alice', 25);
const person2 = createPerson('Bob', 30);
缺点是无法识别对象类型(所有实例的构造函数都是Object
),且方法会在每个实例中重复创建。
构造函数模式
构造函数通过new
操作符调用,自动创建新对象并绑定this
。约定构造函数名称首字母大写。
function Person(name, age) {
this.name = name;
this.age = age;
this.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
}
const person = new Person('Alice', 25);
console.log(person instanceof Person); // true
虽然解决了对象类型识别问题,但方法仍然在每个实例中重复定义,浪费内存。
原型模式
利用原型链共享属性和方法,所有实例共享同一组方法,减少内存消耗。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
const person1 = new Person('Alice', 25);
const person2 = new Person('Bob', 30);
console.log(person1.greet === person2.greet); // true
缺点是所有实例共享引用类型属性时可能产生意外修改。
组合模式(构造函数+原型)
结合构造函数和原型的优点,实例属性通过构造函数定义,共享方法通过原型定义。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype = {
constructor: Person,
greet() {
console.log(`Hello, my name is ${this.name}`);
}
};
const person = new Person('Alice', 25);
这是ES5时代最常用的对象创建模式。
动态原型模式
将原型方法的定义封装在构造函数中,保持代码集中性,同时避免重复初始化原型。
function Person(name, age) {
this.name = name;
this.age = age;
if (typeof this.greet !== 'function') {
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
}
}
Object.create()
直接基于现有对象创建新对象,无需构造函数。
const personProto = {
greet() {
console.log(`Hello, my name is ${this.name}`);
}
};
const person = Object.create(personProto);
person.name = 'Alice';
person.age = 25;
适合需要精确控制原型链的场景。
ES6类语法
class
语法糖本质仍是基于原型的继承,但提供了更清晰的语法结构。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
const person = new Person('Alice', 25);
支持静态方法、继承等特性:
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade;
}
study() {
console.log(`${this.name} is studying`);
}
}
单例模式
确保一个类只有一个实例,并提供全局访问点。
const singleton = (function() {
let instance;
function init() {
return {
name: 'Singleton',
log() {
console.log('I am the only one');
}
};
}
return {
getInstance() {
if (!instance) {
instance = init();
}
return instance;
}
};
})();
const s1 = singleton.getInstance();
const s2 = singleton.getInstance();
console.log(s1 === s2); // true
对象解构与属性简写
ES6新增的语法特性可以简化对象创建过程。
const name = 'Alice';
const age = 25;
const person = {
name,
age,
['id_' + Math.random().toString(36).substr(2)]: true
};
const { name: personName } = person;
console.log(personName); // Alice
使用Symbol作为属性键
Symbol可以创建唯一的对象属性键,避免属性名冲突。
const id = Symbol('id');
const person = {
[id]: '123',
name: 'Alice'
};
console.log(person[id]); // 123
console.log(Object.keys(person)); // ['name']
不可变对象
通过Object.freeze()
或第三方库创建不可变对象。
const person = Object.freeze({
name: 'Alice',
address: Object.freeze({
city: 'Beijing'
})
});
person.name = 'Bob'; // 静默失败(严格模式报错)
代理对象(Proxy)
使用Proxy可以创建具有自定义行为的对象。
const handler = {
get(target, prop) {
return prop in target ? target[prop] : 'Not found';
}
};
const person = new Proxy({ name: 'Alice' }, handler);
console.log(person.name); // Alice
console.log(person.age); // Not found
对象池模式
对于创建成本高的对象,可以通过对象池复用实例。
class ObjectPool {
constructor(createFn) {
this.createFn = createFn;
this.pool = [];
}
acquire() {
return this.pool.length ? this.pool.pop() : this.createFn();
}
release(obj) {
this.pool.push(obj);
}
}
const pool = new ObjectPool(() => ({ id: Date.now() }));
const obj1 = pool.acquire();
pool.release(obj1);