面向对象与原型(二)

     判断属性是在构造函数还是在原型里:

     1.hasOwnProperty(属性名)---->>>此方法判断属性是否在构造函数里。是,则返回true,

否,则返回false

     2.in 操作符的判断范围在构造与原型中,只要在两个地方之一或都有该属性,则返回true

     3.没有直接的方法来判断属性是否在原型中。但从以上两个方法中,可以推导一个方法出

来,用于判断属性是否在原型中,如下:

        function isInPrototype(object,property){

               return  !object.hasOwnProperty(property) && (property in object)

        }

      若该方法返回true,则表示该属性在原型中,而且只在。

 

      用字面量方式创建原型:

      function Box(){};
      Box.prototype={ 
             name:'Lee',
             age:100,
             run:function(){
             return  this.name+this.age+'运行中...';
             }
      };

      字面量创建的方式使用constructor属性不会指向实例, 而会指向Object, 构造函数创建
的方式则相反。
如果想让字面量方式的constructor指向实例对象,那么可以这么做:     

      function  Box(){};

      Box.prototype={ 

            constructor:Box,

             name:'Lee',

             age:100,

             run:function(){

             return  this.name+this.age+'运行中...';

             }
       };

      字面量方式为什么constructor会指向Object?因为Box.prototype={};这种写法其实就是创

建了一个新对象。而每创建一个函数,就会同时创建它prototype,这个对象也会自动获取

constructor属性。 所以, 新对象的constructor重写了Box原来的constructor, 因此会指向新对

象,那个新对象没有指定构造函数,那么就默认为Object。

   

      原型对象不仅仅可以在自定义对象的情况下使用, 而ECMAScript内置的引用类型都可以使用

这种方式,并且内置的引用类型本身也使用了原型。

      alert(Array.prototype.sort);         //sort就是Array类型的原型方法
      alert(String.prototype.substring);        //substring就是String类型的原型方法
      String.prototype.addstring=function(){      //给String类型添加一个方法
              return this+',被添加了! ';       //this代表调用的字符串
      };
      alert('Lee'.addstring());               //使用这个方法。

     //尽管给原生的内置引用类型添加方法使用起来特别方便,但我们不推荐使用这种

    //方法。因为它可能会导致命名冲突,不利于代码维护。

 

      原型的最大优点是共享,同时这也是它最大的缺点。原型中所有属性是被很多实例共享的, 共享

对于函数非常合适,对于包含基本值的属性也还可以。但如果属性包含引用类型,就存在一定的问题:

     function Box(){};
     Box.prototype={
           constructor:Box,
           name:'Lee',
           age:100,
           family:['父亲','母亲','妹妹']                          //添加了一个数组属性
           run:function(){
                 return  this.name+this.age+this.family;
           }
      };
      var box1=new Box();

      box1.family.push('哥哥');                 //在实例中添加'哥哥'
      alert(box1.run());
      var box2 = new Box();
      alert(box2.run());                          //共享带来的麻烦,也有'哥哥'了

 

      了解决构造传参和共享问题,可以组合构造函数+原型模式:

      function Box(name, age) {             //不共享的使用构造函数
            this.name = name;
            this.age = age;
            this. family = ['父亲', '母亲', '妹妹'];
      };
      Box.prototype = {                      //共享的使用原型模式
            constructor: Box,
            run: function() {
                   return this.name + this.age + this.family;
            }
      };

      这种混合模式很好的解决了传参和引用共享的大难题。 是创建对象比较好的方法。

     

      原型模式, 不管你是否调用了原型中的共享方法, 它都会初始化原型中的方法, 并且在声明

一个对象时, 构造函数+原型部分让人感觉又很怪异, 最好就是把构造函数和原型封装到一起。为

了解决这个问题,我们可以使用动态原型模式

      动态原型模式:

      function Box(name ,age) { //将所有信息封装到函数体内
            this.name = name;
            this.age = age;


            if (typeof this.run != 'function') { //仅在第一次调用的初始化
                   Box.prototype.run= function() {
                         return this.name + this.age + '运行中...';
                   };
             }
       }
       var box = new Box('Lee', 100);
       alert(box.run());

      当第一次调用构造函数时, run()方法发现不存在,然后初始化原型。当第二次调用,就不

会初始化, 并且第二次创建新对象, 原型也不会再初始化了。 这样及得到了封装, 又实现了原

型方法共享,并且属性都保持独立。

      使用动态原型模式,要注意一点,不可以再使用字面量的方式重写原型,因为会切断实例和

新原型之间的联系。

 

      以上讲解了各种方式对象创建的方法, 一般地情形都能满足。

      如果这几种方式都不能满足需求, 可以使用一开始那种模式:

      寄生构造函数(工厂模式+构造函数模式)

      function Box(name,age){ 

           var obj=new Object();

           obj.name=name;

           obj.age=age;

           obj.run=function(){

                return this.name+this.age+'运行中...';

          };

          return  obj;
       }
       这种模式比较通用, 但不能确定对象关系,所以,在可以使用之前所说的模式时,不建

议使用此模式。

       在什么情况下使用寄生构造函数比较合适呢?假设要创建一个具有额外方法的引用类型。

由于之前说明不建议直接String.prototype.addstring,可以通过寄生构造的方式添加。

       function myString(string){

            var str=new String(string);

            str.addstring=function(){

                  return this+',被添加了! ';

            };

           return str;

      }

      var box=new myString('Lee');      //比直接在引用原型添加要繁琐好多

      alert(box.addstring());

 

 

      在一些安全的环境中, 比如禁止使用this和new, 这里的this是构造函数里不使用this,

这里的new是在外部实例化构造函数时不使用new。这种创建方式叫做稳妥构造函数。

      function Box(name,age){

           var obj=new Object();

           obj.run=function(){

                 return name+age+'运行中...'; //直接打印参数即可

           };

           returnobj;

       }

       var box=Box('Lee',100); //直接调用函数

       alert(box.run());

       稳妥构造函数和寄生类似。

 

posted @ 2016-01-13 11:21  西风.烈马  阅读(130)  评论(0编辑  收藏  举报