javascript中创建对象的几种设计模式

      javascript中利用Object构造函数和对象字面量的方法都可以创建单个对象,但它们有个明显的缺点就是:使用同一个接口创建很多对象,会产生大量的重复代码。为了解决这个问题,故而产生了诸多的设计模式:

一.工厂模式

   其主要思想是用函数封装以特定接口创建对象的细节,下面是《JavaScript高级程序设计》的例子:

 1 function createPerson(name,age,job){
 2        var o = new Object();
 3        o.name = name;
 4        o.age = age;
 5        o.job = job;
 6        o.sayName = function(){
 7                alert(this.name);
 8        };
 9        return o;    
10 }
11 var person1 = createPerson("Nicholas",29,"Software Engineer");
12 var person2 = reatePerson("Greg",27,"Doctor");

      优点:解决了创建多个相似对象的问题,避免了大量重复的代码;

      缺点:不能进行对象识别,即如何才能知道实例的对象的类型;

二.构造函数模式

    其主要思想是:创建自定义的构造函数,从而定义自定义对象类型的属性和方法,下面是例子:

function Person(name,age,job){//构造函数始终都应该以一个大写字母开头
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
           alert(this.name);
    }
}
var person1 = new Person("Nicholas",29,"Software Engineer");
var person2 = new Person("Greg",27,"Doctor");

  它和工厂模式的不同:没有显式地创建对象;直接将方法和属性传给this对象;没有return语句。

   创建person的实例会经过四个步骤:1.创建一个新对象;

                                                 2.将构造函数的作用域赋给新对象;

                                                 3.执行构造函数中的代码;

                                                 4.返回新对象。

  优点:解决了对象识别的问题,可以用alert(person1 instanceof Person)来进行对象识别;

  缺点:构造函数中的每个方法都要在每个实例上重新创建一遍,即以这种方式创建函数会导致不同的作用域链和标识符解析。如上面的例子,我们完全可以将sayNname方法放在           外面。

三.原型模式

    主要思想:我们创建的每个函数都有一个prototype属性,它是一个指针,指向一个对象,该对象中可以包含由特定类型的所有实例共享的属性和方法。下面是例子:

 1 function Person(){
 2 }
 3 Person.prototype.name = "Nicholas";
 4 Person.prototype.age = 29;
 5 Person.prototype.job = "Software Engineer";
 6 Person.prototype.sayName = function(){
 7         alert(this.name); 
 8 }
 9 var person1 = new Person();
10 person1.sayName();//"Nicholas"
11 var person2 = new Person();
12 person2.sayName();//"Nicholas"
13 alert(person1.Sayname == person2.sayName);//true

    涉及到的方法:isPrototypeOf():alert(Person.prototype.isPrototypeOf(person1))//true

                       Objesct.getPrototypeOf():alert(Object.getPrototypeOf(person1)==Person.prototye)//true

                       hasOwnProperty():可以用来查找一个属性是否是在实例中,它不会再实例的原型中查找。如alert(person1.hasOwnProperty(""name"))

                       in操作符,会访问原型,同时使用in操作符和hasOwnProperty()可以知道属性到底是存在于实例对象中还是存在于原型中

     注意事项:搜索某个对象的属性时,首先从对象实例本身开始,如果在实例中找到了该属性,则返回该属性的值,如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找该属性。故实例中若存在和原型对象中同名的属性或者方法,会屏蔽原型中相对应的属性和方法。如若不想屏蔽,可以用delete删除实例属性,则可以重新访问原型中的属性。

      优点:使用原型对象可以让所有对象实例共享它所包含的属性和方法,不必再对象实例中定义对象实例的信息。

      缺点:所有实例在默认情况下回取得相同的值,特别是当原型中有引用类型的值时,任何一个对象实例修改的信息都会在其他实例中表现出来,显然这不是想要的结果。

四.组合使用构造函数模式和原型模式

     这是最常见的方式,其主要思想是构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性,集两种模式之长。下面是例子:

function Person(name,age,job){
      this.name = name;
      this.age = age;
      this.job = job;
      this.friends = ["Shelby","Court"];
}
Person.prototype = {
      constructor:Person,
      sayName:function(){
            alert(this.name);
}
var person1 = new Person("Nicholas",29,"Software Engineer");
var person2 = new Person("Greg",27,"Doctor");
person1.friends.push("Van");
alert(person1.friends);  //"Shelby Count, Van"
alert(person2.friends);  //"shelby,Cpout"
alert(person1.sayName == person2.sayName);true

优点:构造函数模式和原型模式的优点它都有;

缺点:独立的构造构造函数和原型可读性不好。

五.动态原型模式

 1 function Person(name,age,job){
 2          //属性
 3         this.name = name;
 4         this.age = age;
 5         this.job = job;
 6         //方法
 7         if(typeof this.sayName != "function"){
 8               Person.prototype.sayName = function(){
 9                        alert(this.name);
10               };
11          }
12 }

优点:保持了构造函数和原型的优点,解决了可读性的问题,很完美。(这段代码只会在初次调用构造函数时才会执行,此后原型已经完成初始化,不需要再做什么修改了)

六.寄生构造函数模式

    基本思想:创建一个函数,该函数的作用仅仅是封装对象的代码,然后再返回新创建的对象

    使用场景:在特殊情况下用来为对象创建构造函数,比如想创建一个具有额外方法的特殊数组,由于不能直接修改Array构造函数,因此可以使用这个模式。

七.稳妥构造函数模式

    道格拉斯发明了稳妥对象这个概念,稳妥对象指的是没有公共属性,而且其方法也不引用this的对象。

    稳妥对象最适合在一些安全的环境中,或者在防止数据被其他应用程序改动时使用。

    特点:新创建对象的实例方法不引用this;不使用new操作符调用构造函数。

posted @ 2017-05-03 14:46  孙冬冬-入门前端  阅读(301)  评论(0编辑  收藏  举报