zoukankan      html  css  js  c++  java
  • 面向对象与原型(二)

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

         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());

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

  • 相关阅读:
    AC自动机
    HDU
    2020牛客寒假算法基础集训营3 B 牛牛的DRB迷宫II
    POJ 3784 Running Median【维护动态中位数】
    CodeForces
    HDU 2444 The Accomodation of Students【二分图最大匹配问题】
    POJ 1201 Intervals【差分约束】
    POJ 2976 Dropping tests【0/1分数规划模板】
    2019牛客暑期多校训练营(第七场)A.String【最小表示法】
    POJ 1287 Networking【kruskal模板题】
  • 原文地址:https://www.cnblogs.com/xbj-2016/p/5126671.html
Copyright © 2011-2022 走看看