JavaScript创建自定义对象的五种常用方式详解

作者:异步漫步

时间:2026-10-22

浏览:171

本文系统总结了JavaScript中创建自定义对象的五种常用方式。从简单的对象字面量到工厂模式,再到构造函数模式、原型模式,最后介绍最推荐的组合使用构造函数和原型模式。详细分析了各模式的优缺点,包括代码复用、内存占用及属性共享等问题,帮助开发者根据实际需求选择最佳方案。

文章目录

本文详细介绍JavaScript中创建自定义对象的几种主流实现方式,旨在为开发者提供实用的参考与对比分析。

1. 对象字面量方式

对象字面量是构建自定义对象的首选方法,因其语法简洁、使用便捷。


var per = {
 name:'zhangsan',
 age:25,
 job:'html',
 sayName:function(){
  alert(this.name);
 }
}

主要缺点在于:若需通过同一接口创建大量对象,会导致代码高度重复。例如,若要创建另一个名为per1的对象,必须重新编写相同的代码结构,仅修改具体的属性值,缺乏复用性。

2、工厂模式

工厂模式旨在抽象创建具体对象的过程。鉴于ECMAScript缺乏直接创建类的机制,开发人员利用函数封装创建对象的细节,通过特定接口生成对象,示例如下:


function createPerson(name,age,job){
 var o = new Object();
 o.name = name;
 o.age = age;
 o.job = job;
 o.sayName = function(){
  alert(this.name);
 }
 return o;
}
var person1 = createPerson('zhang',30,'java');
var person2 = createPerson('zhao',25,'php');

函数createPerson()根据接收到的参数构建包含完整信息的Person对象。该函数可被多次调用,每次均返回包含三个属性及一个方法的对象实例。

尽管工厂模式解决了创建多个相似对象的问题,但未解决对象识别问题,即无法准确判断一个对象的具体类型。

3、构造函数模式

利用构造函数模式,可将前述示例重写如下:


function Person(name,age,job){
 this.name= name;
 this.age = age;
 this.job = job;
 this.sayName = function(){
  alert(this.name);
 }
}
var person1 = new Person('zhang',30,'java');
var person2 = new Person('zhao',25,'php');

定义自定义构造函数使得实例能够被标识为特定类型,这是构造函数模式优于工厂模式的关键所在。

然而,构造函数模式的主要缺陷是:每个实例上的方法都会重新创建一遍。在示例中,person1和person2均拥有名为sayName()的方法,但它们并非同一个Function实例。创建执行相同任务的多个Function实例既无必要也不高效。鉴于this对象的存在,无需在代码执行前将函数绑定至特定对象。因此,可通过将函数定义移至构造函数外部来解决此问题。


function Person(name,age,job){
 this.name= name;
 this.age = age;
 this.job = job;
 this.sayName = sayName();
}
function sayName(){
  alert(this.name);
}
var person1 = createPerson('zhang',30,'java');
var person2 = createPerson('zhao',25,'php');

在此示例中,我们将sayName()函数的定义移至构造函数外部。在构造函数内部,将sayName属性指向全局的sayName函数,从而使person1和person2共享全局作用域中定义的同一个sayName()函数。这解决了函数重复创建的问题,但引入了新问题:在全局作用域中定义的函数仅服务于特定对象,使得全局作用域的定义显得名不副实。若对象需定义大量方法,则需定义相应数量的全局函数。这些问题可通过原型模式进一步解决。

4、原型模式

每个函数均拥有一个prototype(原型)属性,该属性是一个指向对象的指针,该对象包含可由特定类型所有实例共享的属性和方法。使用原型对象的优势在于,所有对象实例可共享其包含的属性和方法。


function Person(){}
Person.prototype.name = 'zhang';
Person.prototype.age = '22';
Person.prototype.job = 'html5';
Person.prototype.sayName = function(){
 alert(this.name);
};
var person1 = new Person();
var person2 = new Person();

原型模式同样存在缺点。首先,它省略了向构造函数传递初始化参数的环节,导致所有实例在默认情况下拥有相同的属性值。虽带来一定不便,但这并非原型模式的最大问题。其最大问题源于共享本性。

原型中的属性被多个实例共享,这对函数而言非常合适。对于包含基本值的属性,尚可通过在实例上添加同名属性来隐藏原型中的对应属性。然而,对于包含引用类型的属性,问题则较为突出。


function Person(){}
Person.prototype = {
 constructor:Person,
 name:'zhang',
 age :'22',
 job :'html5',
 friends:['wang','li'],
 sayName : function(){
  alert(this.name);
 }
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push('zhao');
alert(person1.friends); //'wang,li,zhao'
alert(person2.friends); //'wang,li,zhao'
alert(person1.friends === person2.friends); //true

从上述打印结果可知,为何很少有人单独使用原型模式:实例通常需要具备属于自己的完整属性集。

5、组合使用构造函数模式和原型模式

组合使用构造函数模式和原型模式是创建自定义类型的最常见方式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性。结果,每个实例拥有自己的一份实例属性副本,同时共享对方法的引用,从而最大限度地节省内存。


function Person(name,age,job){
 this.name= name;
 this.age = age;
 this.job = job;
 this.friends = ['wang','li'];
}
Person.prototype = {
 constructor:Person,
 sayName : function(){
  alert(this.name);
 }
}
var person1 = new Person('zhang',26,'java',);
var person2 = new Person('sun',25,'php');
person1.friends.push('zhao');
alert(person1.friends); //'wang,li,zhao'
alert(person2.friends); //'wang,li'
alert(person1.friends === person2.friends); //false

在示例中,实例属性均在构造函数中定义,而由所有实例共享的属性constructor和方法satName()则在原型中定义。修改person1.friends(向其添加新字符串)不会影响person2.friends,因为它们引用了不同的数组实例。

更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章