在JavaScript中创建对象,对于JavaScript开发者来说,会有很多种方法去创建,本文将剖析JavaScript原型设计模式,在大多数地方,可以使用这种原型属性来分享对象中的实例方法。
1.定义内部方法(Defining Methods Internally)
在所有创建对象的方式中,这大概是最简单,最直观的方式了。使用function定义构造函数,在设置所有对象的属性和方法时,只要在前面追加this就可以了。你或许没有意识到,这个特殊的模型是非常耗内存的,原因就是这个getInfo()方法在每次新建一个实例时都要被创建,如果你仅仅是创建几个对象,那么也不会占太多的内存。
- function Car(make, model, level, color, warranty) {
- this.make = make;
- this.model = model;
- this.level = level;
- this.color = color;
- this.warranty = warranty;
- this.getInfo = function() {
- return this.make + ', ' + this.model + ', ' + this.level + ', '+ this.color + ', ' + this.warranty;
- };
- }
- var aCar = new Car('Acura', 'TL', 'Sport', 'blue', 5);
- alert(aCar.getInfo()); //displays Acura, TL, Sport, blue, 5
2.添加外部原型(Methods Added Externally to the Prototype)
通过给对象方法添加构造函数原型来分享所有对象方法。首先要定义构造函数和属性,然后把方法添加到函数原型属性中。这样做的好处是你可以随时添加方法并且被该类型的所有对象(即使是已经被实例化的对象)识别。
- function Car(make, model, level, color, warranty) {
- this.make = make;
- this.model = model;
- this.level = level;
- this.color = color;
- this.warranty = warranty;
- }
- Car.prototype.getInfo = function() {
- return this.make + ', ' + this.model + ', ' + this.level + ', '+ this.color + ', ' + this.warranty;
- };
- var aCar = new Car('Acura', 'TL', 'Sport', 'blue', 5);
- alert(aCar.getInfo()); //displays Acura, TL, Sport, blue, 5
- Car.prototype.accelerate = function() {
- return 'How fast?';
- };
- alert(aCar.accelerate()); //displays "How fast?"
3.原型模式(The Prototype Pattern)
比前面那个例子稍微先进点的方式,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。在功能上,这两个模型并没有什么不同,它可以将所有的方法组合在一起。
- function Car(make, model, level, color, warranty) {
- this.make = make;
- this.model = model;
- this.level = level;
- this.color = color;
- this.warranty = warranty;
- }
- Car.prototype = {
- getInfo: function () {
- return this.make + ', ' + this.model + ', ' + this.level + ', '+ this.color + ', ' + this.warranty;
- }
- };
4.The Revealing Prototype Pattern
与之前的模式比起来,这种对象的创建会有很多显著的效果,第一个是在一个构造函数中,它可以包围所有对象的属性和方法。第二个优点是我们可以定义私有对象成员,并且通过用var关键字定义本地变量。
- var Car = function(make, model, level, color, warranty) {
- var _make = make,
- _model = model,
- _level = level,
- _color = color,
- _warranty = warranty;
- return {
- getInfo: function () {
- return _make + ', ' + _model + ', ' + _level + ', '+ _color + ', ' + _warranty;
- }
- };
- };
5.Extending the Revealing Prototype Pattern
然而,Revealing Prototype Pattern的另外一个突出优点是,它使扩展和/或覆盖现有的功能更直接一点。让我们来扩展Car对象,通过定义它的构造函数和分配一个新的Car实例给UsedCar原型去创建一个UsedCar:
- var UsedCar = function(mileage) {
- //Define a variable unique to each instance of UsedCar
- this.mileage = mileage;
- };
- UsedCar.prototype = new Car('Honda', 'Civic', 'LX', 'gray', 2);
同样,我们可以重写Car对象的功能仅仅用相同的函数名字来替换它,通过扩展我们可以重用getInfo()这个方法,这样对UsedCar会有好处的。我们可以从UsedCar的原型中获得getInfo()方法,因为我们构建了一个Car实例在这。使用封闭,我们可以追加UsedCar的里程,通过getInfo()这个方法进行输出。
- var UsedCar = function(mileage) {
- //Define a variable unique to each instance of UsedCar
- this.mileage = mileage;
- };
- UsedCar.prototype = new Car('Honda', 'Civic', 'LX', 'gray', 2);
- var aUsedCar = new UsedCar(50000);
- alert(aUsedCar.getInfo()); //displays Honda, Civic, LX, gray, 2
- //this will add the mileage to getInfo()'s output
- UsedCar.prototype.getInfo = function(superGetInfo) {
- return function() { return superGetInfo() + ', '+ this.mileage; };
- }(UsedCar.prototype.getInfo);
- alert(aUsedCar.getInfo()); //displays Honda, Civic, LX, gray, 2, 50000
以上我们总结了在JavaScript中最常见的几种原型模式,如果你有其他不同的见解,可以留言与我们讨论。