本文深入解析 JavaScript 中两种核心的对象创建模式:混合构造函数与原型方式,以及动态原型方式。通过对比分析,阐述如何将实例属性与共享方法分离,利用原型链实现内存优化,并介绍通过标志位控制原型方法初始化次数的动态原型技巧,帮助开发者写出更规范、高效的代码。
JavaScript 对象创建基础模式概述
在 JavaScript 日常开发中,构建对象最基础的两种实现路径如下所示。
1. 混合构造函数与原型方式(重点)
混合构造函数与原型方式
具体代码实现如下:
function car (sColor,iNumbers){ // 构造函数仅负责定义对象的所有非函数属性,即实例属性
this.color = sColor;
this.numbers = iNumbers;
this.dirvers = new Array ("Jone","Leon");
}
car.prototype.showColor = function (){ // 原型模式仅负责定义对象的所有函数属性,即共享方法
alert(this.color);
}
var car1 = new car("red");
var car2 = new car("yellow");
car1.showColor)();
car2.showColor)(); 核心原理总结:当使用 new 关键字创建 car1 和 car2 两个实例时,它们各自继承构造函数 car 中定义的所有非函数属性(如 color、numbers 等)。此时,showColor 方法被定义在 car 的原型对象上,因此 car1 和 car2 均通过原型链引用同一个 showColor 方法。若将方法定义在构造函数内部,则每次实例化都会重新创建该方法,导致内存浪费。例如创建 100 个 car 实例,就会生成 100 个相同的函数副本。因此,将非函数属性与函数属性分离书写是必要的优化手段。
2. 动态原型方式(重点)
动态原型方式实现
动态原型模式的具体代码实现如下:
function car (sColor,iNumbers){ // 构造函数仅负责定义对象的所有非函数属性,即实例属性
this.color = sColor;
this.numbers = iNumbers;
this.dirvers = new Array ("Jone","Leon");
if(typeof car._initialized=="undefined"){ // 首次执行时,car._initialized 为 undefined,条件成立,执行后续代码
car.prototype.showColor = function (){
alert(this.color);
}
}
car._initialized = true; // 设置初始化标志
执行至此便停止后续逻辑,不再重复执行。此处 car._initialized 是构造函数本身的属性,而非原型属性。若将其设为原型属性,每次 new 实例都会改变该属性,导致方法被重复构造。正因如此,当 car._initialized 为 undefined 时,仅执行一次方法定义,随后将其设为 true。这一操作修改的是函数自身的属性,而非原型属性,因此外部 new 实例无法改变此状态。红色代码块的核心目的仅在于确保该方法定义逻辑只执行一次,避免重复构造。
}
var car1 = new car ("red");
var car2 = new car ("yellow");
car1.showColor();
car2.showColor(); 总结:上述两种模式在最终效果上是一致的,均能正确创建对象并共享方法。
模式一:混合构造函数与原型方式。该方式将实例属性与共享方法分开定义,使得 new 新对象时不会重复构造函数,实例仅引用原型中的方法和属性。其缺点在于代码结构上缺乏封装感,尽管不影响功能运行。
模式二:动态原型方式。该方式借鉴 Java 的编程风格,将所有属性和方法封装在同一个函数体内,使代码看起来更像一个标准的“类”。(注:JavaScript 中本质上没有类,若强行理解,可将其视为 function 类)。其缺点在于使用 if 语句进行条件判断,代码可读性稍显不佳。