JavaScript 对象定义的演进:从工厂模式到组合构造函数

作者:纸飞机

时间:2026-10-23

浏览:502

本文系统梳理 JavaScript 中创建对象的几种核心模式。从基础的直接赋值到工厂模式,再到构造函数法,深入分析了各自在内存管理与代码复用上的优缺点。重点讲解了原型模式的局限性及其引发的引用类型共享问题,最终引出结合构造函数与原型的组合模式,这是目前定义复杂对象最常用且高效的方法。

文章目录

工厂模式与构造函数法

工厂模式


初级开发者在定义对象时,往往采用直接实例化的方式。


var obj = new Object();


obj.name = "hero";


obj.showName=function (){alert(this.name);}


这种写法存在明显的缺陷:当需要在程序多处复用该对象时,必须重复编写大量相似代码。为了解决代码冗余问题,工厂模式应运而生。


function createObj()


{

var obj = new Object();


obj.name="hero";


obj.showName=function (){alert(this.name);}


return obj;


}

var obj1 = createObj();


var obj2 = createObj();


除了工厂模式,另一种常见做法是使用构造函数法。


function obj (name)


{

this.name=name;


this.showName= function (){alert(this.name);}


}

上述方法将生成对象的逻辑封装起来,避免了重复使用 new 关键字。为了进一步提升灵活性,可以对 createObj 函数进行改进,使其接收参数而非使用固定的默认值。


function createObj(name)


{

var obj = new Object();


obj.name=name;


obj.showName=function (){alert(this.name);}


return obj;


}

var obj1 = createObj("hero");


var obj2=createObj("dby");


然而,这种方法存在一个性能隐患:每次调用 createObj 函数时,都会重新创建一个新的 showName 函数实例。这意味着每个对象都拥有自己独立的 showName 版本,造成了不必要的内存浪费。


function showName()


{

alert(this.name)


}

function createObj(name)


{

var obj = new Object();


obj.name=name;


obj.showName=showName;


return obj;


}

通过将函数定义在外部并赋值给对象属性,成功解决了重复创建函数的问题。


原型模式的局限性

原型方式


这种方法主要利用对象的 prototype 属性来实现。


function obj()


{}

obj.prototype.name="hero";


obj.prototype.showName=function()


{

alert(this.name);


}

虽然原型方式看起来比工厂模式更完美,但它存在一个关键缺陷:没有构造函数,属性是通过 prototype 指定的。在实际应用中,所有实例的属性值完全相同,这往往不符合需求。更严重的安全隐患在于引用类型的共享问题。


obj.prototype.nameArray = new Array("hero","dby");


然后


obj1 = new obj();


obj2 = new obj();


obj1.nameArray.push("lxw");


如果在 obj2 中查看 nameArray,会发现其中也包含了 "lxw"。这是因为 obj1 和 obj2 的 nameArray 指向的是内存中的同一个引用数组,修改其中一个会影响另一个。


因此,单纯的原型方式并非理想解决方案。


组合构造函数模式

需要改进


最佳实践是结合构造函数与原型:在构造函数中定义属性,在原型中定义方法。


例如


fuction obj(name)


{

this.name = name


this.nameArray = new Array("hero","dby");


}

obj.prototype.showName = function(){alert(this.name)}


在这种组合模式下,所有非函数属性都在构造函数内部创建,而函数属性则通过 prototype 方式创建。这样,obj1 修改 nameArray 的值不会影响 obj2 的 nameArray,同时所有对象共享同一个 showName 函数,既保证了数据隔离又避免了内存浪费。


这种模式基本达到了完美平衡,其他修饰性技巧可根据具体需求自行探索。


单例模式变体与完整实例

这里补充一个单例模式的变体示例:


function obj (name)


{

this.name = name;


this.nameArray=new Array("hero","dby");


if(typeof obj._initialized=='undefined')


{

obj.prototype.showName=function(){alert(this.name);}


obj._initialized="true";


}
}

这并非严格的单例模式,而是一种优化手段:在构造对象时,先判断某个属性是否已定义。若未定义,则使用原型方法定义对象函数;若已定义,则不再重复定义。该 prototype 方法仅被创建和赋值一次。


经过上述优化,方案已相当完善。


以上为个人理解,旨在提供有益参考。如有不完善之处,欢迎联系指正。


以下是一个完整的实例代码:


function Rectangle(name,color,width,heigth){


this.name=name;


this.color=color;


this.width=width;


this.heigth=heigth;


}

Rectangle.prototype.area=function(){


return this.width*this.heigth


}

Rectangle.prototype.show=function(){


document.write(this.name+" "+this.color+" "+this.width+" "+this.heigth+"<br/>");


document.write(this.area());


}

var obj1= new Rectangle("Rectangle","red",15,20);


obj1.show();}

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章