关于Js中对象的创建

1、概述:


尽管object构造函数或者字面量对象都可以创建单个对象,但是该方法存在一个明显的不足:即一个接口创建了多个对象,产生了代码的重复,为此,引入工厂模式(抽象类创建具体对象的过程)的派生方法,来解决多个对象相似的问题:


2、工厂模式:


实现方法:用函数来封装特定接口创建对象的细节,如下:

   function createProduct(id,name,price){

    var obj = new Object();

    obj.id = id;

    obj.name = name;

    obj.price = price;

    obj.produceProcess = function(){

alert(“First…Second…”);

};

return obj;

 }

var productOne = new createProduct(“1″,”Apple”,”1.20$”);

var productTwo = new createProduct(“2″,”Peach”,”0.50$”);

存在问题:解决了多个对象相似的问题,关于对象识别,即确认对象类型,没有给出解决办法,进而引入构造函数模式:


3、构造函数模式:


 ECMAScript(European Computer Manufacturers Association Script)中的构造函数可以用来创建特定类型的对象,也可以自定义构造函数,进而自定义对象类型的属性与方法,重写工厂模式的例子如下:

   function Product(id,name,price){

    this.id = id;

    this.name = name;

    this.price = price;

    this.produceProcess = function(){

alert(“First…Second…”);

};

 }

var productOne = new Product(“1″,”Apple”,”1.20$”);

var productTwo = newProduct(“2″,”Peach”,”0.50$”);

自定义模式意味着可以把它的实例标识为一种特定的类型

存在问题:每个方法都要在每个实例中创建一遍,解决方案:将函数的定义转移到构造函数的外部,将produceProcess属性设置为全局的produceProcess函数;如下:

   function Product(id,name,price){

    this.id = id;

    this.name = name;

    this.price = price;

    this.produceProcess = produceProcess;

 }

function produceProcess  (){

alert(“First…Second…”);

};

不足之处:全局变量只能被某个对象所调用,不能“全局化”,定义多个方法,同时即需要定义多个全局变量;引入原型模式解决该问题;


4、原型模式:


每一个函数都具有原型(prototype)属性,该属性是一个指针,指向一个对象,该对象包含由特定类型的所有实例共享的属性和方法,即一个原型对象可以让所有对象实例来共享它所包含的属性和方法,从而不必在构造函数中定义对象实例的信息,而是将这些信息添加到原型对象中去:具体实现如下:

function Product(){}

Product.prototype.id = “1”;

Product.prototype.name = “Apple”;

Product.prototype.price = “1.20$”;

Product.prototype.produceProcess = function(){

alert(“First…Second…”);

};

var productOne = new Product();

productOne.produceProcess();         //First…Second…

var productTwo = new Product();

productTwo .produceProcess();         //First…Second…

存在问题:这种共享对于函数来说,比较合适,对于包含引用类型值的属性来说,存在很大问题,如果要给一个包含引用类型值添加或者删除一个它的属性,则原型模式的优点变成了它的缺点,使得这种操作无效,如下:

function Product(){}

Product.prototype = {

constructor: Product,

id : “1”,

name : “Apple”,

price : “1.20$”,

contained : [“seed”,”pulp”],                             //苹果包含种子和果肉,但是………

produceProcess : function(){

alert(“First…Second…”);

};

}

var productOne = new Product();

var productTwo = new Product();

//但是第二个苹果里面还有一只虫子呢,怎么办?

productTwo.contained .push(“worm”);

alert(productOne.contained );            // “seed”,”pulp”,”worm“;    第一个苹果怎么也有虫子?

alert(productTwo.contained );            // “seed”,”pulp”,”worm”;

alert(productOne.contained  === productTwo.contained );  //  true  你看,这两苹果都有虫子了

因为不能让苹果都坏掉,所以一般采用构造函数模式和原型模式组合的方法来解决这种问题:


 5、组合模式:


组合模式中:构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性,所以每个实例都会有自己的一份实例属性的副本,同时,共享着对方法的引用,最大程度的节省了内存,如下:

   function Product(id,name,price){

    this.id = id;

    this.name = name;

    this.price = price;

    this.contained = [“seed”,”pulp”];

 }

Product.prototype = {

constructor : Product;

produceProcess : function(){

alert(“First…Second…”);

};

};

var productOne = new Product(“1″,”Apple”,”1.20$”);

var productTwo = newProduct(“2″,”Peach”,”0.50$”);

productTwo.contained.push(“worm”);      //虫虫又来了

alert(productOne.contained );            // “seed”,”pulp”;  

alert(productTwo.contained );            // “seed”,”pulp”,”worm”;    虫虫只在这里吃苹果

alert(productOne.contained  === productTwo.contained ); //false  苹果可以吃了

alert(productOne.produceProcess === productTwo.produceProcess );  // true

好了,这种最流行,最愉快的对象创建方式就这样愉快结束!


6、补遗:


还有几种模式,一并介绍:

  • 动态原型模式:该方法关于是否初始化原型,即使用某个方法前应当对它进行存在性判断,如果不存在,创建一个就行,而且对原型的修改,即会体现在实例中;
  • 寄生构造模式和稳妥构造使用比较少,详细说明,此处暂略!

7、参考资料:


  • 《JavaScript高级程序设计》 Nicholas C.Zakas 著 人民邮电出版社;

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注