JavaScript享元模式:原理、实现与性能对比
本文通过两个JavaScript实例对比,深入解析享元模式原理。首先展示未使用享元模式时大量相似对象导致的内存开销,随后演示如何利用享元模式结合简单工厂,将不变状态与变化状态分离,从而显著降低空间复杂度。文章包含完整代码示例及性能测试数据,帮助开发者理解如何在实际项目中应用享元模式进行内存优化。
JavaScript享元模式概述
本文通过具体实例详细解析JavaScript中享元模式的原理及其实际应用方法,旨在为读者提供清晰的参考。
享元模式的核心在于提升性能,特别是优化空间复杂度。该设计模式能够有效避免创建大量结构相似但仅细微差异的类,从而减少系统开销。
未使用享元模式的性能分析
为了直观展示享元模式的优势,我们将通过两个对比案例进行分析:第一个案例不使用享元模式,重点计算其执行时间与空间占用;第二个案例则引入享元模式进行对比。
设定具体业务场景:某城市需要对大量汽车信息进行登记管理。
首先定义基础汽车类,包含制造商、型号、拥有者、车牌号及最近登记日期等属性。
/**
* 制造商
* 型号
* 拥有者
* 车牌号码
* 最近一次登记日期
*/
var Car = function(make,model,year,owner,tag,renewDate){
this.make = make;
this.model = model;
this.year = year;
this.owner = owner;
this.tag = tag;
this.renewDate = renewDate;
this.getMake = function(){
return this.make;
}
}
接着,引入装饰者模式来封装函数执行时间的计算逻辑,以便后续评估不同方案的性能差异。
//装饰者 .. 计算函数的耗时
var simpleProfiler = function(componet){
this.componet = componet;
this.action = function(methodName){
var self = this;
var method = componet[methodName];
//如果是函数那就进行装饰
if(typeof method == "function"){
var startDate = new Date().getTime();//开始时间
method.apply(self.componet,arguments);
var endDate = new Date();//结束时间
alert(endDate - startDate);
}
}
}
在第一个实例中,假设需要登记4150000辆汽车,我们直接为每一辆车创建独立的对象实例。
var ca = new Array();
function addCar(){
this.begin = function(){
for (var i = 0; i < 4150000; i++) {
ca.push(new Car("BMW","宝马","2017-10-18",
"","GBMW88","2017-10-19"));
}
}
}
new simpleProfiler(new addCar()).action("begin")
使用享元模式的实现方案
在第二个实例中,我们采用享元模式来优化上述登记过程。
定义汽车类时,仅保留制造商、型号和年份等不变的状态信息,而将拥有者、车牌号等可变状态剥离。
/**
* 制造商
* 型号
* 拥有者
* 车牌号码
* 最近一次登记日期
*/
var Car = function(make,model,year){
this.make = make;
this.model = model;
this.year = year;
this.getMake = function(){
return this.make;
}
}
实现一个基于单例模式的简单工厂,用于管理和复用汽车实例。
//单例模式的简单工厂
var myCarInfo = function(){
this.createCar = function(make,model,year,owner,tag,renewDate){
var c = carInfoFactory(make,model,year);
c["owner"] = owner;
c["tag"] = tag;
c["renewDate"] = renewDate;
return c;
}
}
var carInfoFactory = (function(){
var carInfo = {};
return function(make,model,year){
if(carInfo[make+model+year]){
return carInfo[make+model+year];
}else{
var newCar = new Car(make,model,year);
carInfo[make+model+year] = newCar;
return newCar;
a
}
}
})();
同样处理4150000辆汽车的登记需求,但通过工厂方法复用已有的汽车实例。
var test = new myCarInfo();
var startDate = new Date().getTime();
var ca = new Array();
for (var i = 0; i < 4150000; i++) {
ca.push(test.createCar("BMW","宝马","2017-10-18",
"","GBMW88","2017-10-19"))
}
var endDate = new Date();
alert(endDate - startDate);
两种模式的对比结论
对比两个案例的结果可知:未使用享元模式的方案虽然执行时间较短,但消耗了巨大的内存空间;而使用享元模式的方案虽然执行耗时略增,但极大地节省了空间资源。
第一种情况(无享元模式)的图解显示,系统每次都会生成完全相同的独立实例,导致内存中堆积大量重复数据。

第二种情况(享元模式)的图解展示了“内在部分(不变状态)”与“外部状态(变化状态)”的结合方式,通过共享内在部分来复用对象。

感兴趣的技术人员可以使用在线HTML/CSS/JavaScript前端代码调试运行工具:http://tools.jb51.net/code/WebCodeRun 来测试上述代码的实际运行效果。
如需进一步了解JavaScript相关知识,建议查阅本站专题:《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》。
希望本文关于JavaScript程序设计的阐述能对大家有所帮助。
UmiJS 项目构建速度优化与打包体积精简技巧
2026-11-04 22:37:09
原生JS操作DOM与Vue/React虚拟DOM的本质区别
2026-11-04 17:52:27
怎么使用console.group和table优化JS日志可读性
2026-11-03 23:14:34
基于AST抽象语法树的JS代码反混淆实战教程
2026-11-03 21:22:24
JS手机号输入校验的性能优化与用户体验提升
2026-11-03 19:19:19
