【JavaScript】面向对象与原型

ECMAScript有两种开发模式:

    1、函数式(过程化)

    2、面向对象(OOP

    但是ECMAScript没有类的概念,因此与基于类的语言的对象也有所不同。

 

一、创建对象

 

         var box=new Object();

         box.name='lee';                          //属性

        box.run=function(){                  //方法

                  returnthis.name+'运行中。。。';

           }

         alert(box.run());

 

 

          关于工厂模式方法

 

         因为对象是引用类型值,所以,每次更新这个对象,对象的源值都会改变,要想多整出几个对象,就要再写一个新的对象,从而产生2个不同的对象引用值,但是这样每次创建一个新的对象,要写很多代码,所以用到工厂模式方法。

 

         代码:

         function createObject(name,age){

                var obj=new Object();

                obj.name=name;

                obj.age=age;

                obj.run=function(){

                     returnthis.name+this.age+'运行中。。';

                };

                return obj;

          }

       

         var box1=createObject('lee',100);  

         var box2=createObject('kee',200);

         alert(box1.run());

        alert(box2.run());

 

       工厂模式解决了重复实例化的问题。

 

          关于构造函数

               

          因为工厂模式解决了重复实例化的问题,但是还有一个问题就是识别问题,因为根本无法搞清楚他们到底是那个对象的实例,所以就采用构造函数方法来创建特定对象。

     

           代码:

            function Box(name,age){

                     this.name=name;

                     this.age=age;

                     this.run=function(){

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

                      }

           }

           

            var box1=newBox('lee'100);         //new Box()即可

            var box2=newBox('kee', 200);

 

             alert(box1.run());

             alert( box1  instantof Box);   //很清晰的识别他从属于Box.

 

          采用构造方法就解决了上面两个问题,第一,重复实例化,第二,对象识别的问题,但是这里了并没有new Object(),为什么可以实例化Box()?

 

         采用构造方法,和使用工厂模式的方法不同之处

       1、构造函数方法没有显示的创建对象(new Object());

       2、直接将属性和方法赋值给this对象。

       3 没有return语句。

 

    构造函数方法有一些规范:

    1、函数名和实例化构造名相同且大写(PS:非强制,但这么写有助于区分构造函数和普通函数)。

 

    2、通过构造函数创建对象,必须使用new运算符。

 

  

    上面说了,在构造函数方法里面没有new Object(),没有创建对象,那么它在什么地方创建了一个新的对象?

 

    1、使用了构造函数,并且new 构造函数(),那么后台就执行了new Object();

    2、将构造函数的作用域给新对象,(即new Object()创建出来的对象),而函数体内的this就代表newObject()出来的对象。

 

   3、返回新对象(后台直接返回)

 

 

   对象冒充调用:

   

    为了改变作用域,就用到了对象冒出调用。

 

      var 0=new Object();

      Box.call(o,'jack',200)

      alert(0.run());

 

     这样对象0就可以调用box的方法了。

 

 

二、原型

 

        我们创建的每一个函数都有一个prototype()属性,这个属性是一个对象,用途是包含可以由特定类型的所有实例共享的属性和方法。

 

 

       原型的创建:

       方法一:

          functionBox(){}          //声明一个构造函数

  

          Box.prototype.name='lee';

          Box.prototype.age=100;

          Box.prototype.run=function(){

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

         }

       

       方法二:

            function Box(){};

             

           Box.prototype={

                          name:'lee',

                          age:100,

                          run:function(){

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

                           }

                       };

   

 

     进一步了解构造函数的声明方式和原型模式的声明方式,下面是图示;

     


 


 

     

    判断一个对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf()方法来测试。

     alert(Box.prototype.isPrototypeOf(box));

 

 

   原型模式的执行流程:

  

    1、先查找构造函数实例里的属性或方法,如果有,立即返回。

    2、如果构造函数实例里没有,就去它的原型对象里找,如果有,就返回。

          对象实例仅可以访问原型中的值,不可更改。

 

 

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

    alert(box.hasOwnProperty('name')); //在实例里返回true.

 

 

     原型对象不仅可以在自定义对象的情况下使用,而ECMAScipt内置的引用类型都可以使用这种方式,并且内置的引用类型本身也使用了原型。

 

         

    

因为原型模式的最大优点:共享,也是它的最大的缺点,所以,当我们要保持数据的特性,而不能共享时,我们就用到下面:

 

组合构造函数+原型模式:

 

  function Box(name,age){        //不共享的使用构造函数

         this.name=name;

         this.age=age;

        this.family=['father']

     }

  Box.prototype={                  //共享时使用原型模式

            constructor:Box,

            runfunction(){

                     returnthis.name+this.age+this.family;

               }

             }

 

   为了封装性更好,我们把构造函数和原型封装在一起,叫做:

 

动态原型模式:

    

          functionBox(name,age){    //将所有的写成封装到函数体内

                  this.name=name;

                   this.age=age;

 

                 if(typeofthis.run!='function'){      //仅在第一次调用的初始化

                      Box.prototype.run=function(){

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

        }

 }

}

 

Varbox=new Box('lee',100);

Alert(box.run());

 

 

三、继承

         继承是面向对象中的一个比较核心的概念。其他正统面向对象语言都会用两种方式实现继承,一个是接口实现,一个是继承,而ECMAScript只支持继承,不支持接口实现,而实现继承的方式依靠原型链完成。

 


 

   

 


 

     JavaScript里,被继承的函数称为超类型(父类,基类),继承的函数称为子类型(子类,派生类)。继承也有之前的问题,比如字面量重写原型会中断关系,使用引用类型的原型,子类还无法给超类型传递参数。

 

借用构造函数:

    

       目的:

            为了解决引用共享和超类型无法传参的问题。


 


 

 

组合继承:

      

       目的:

              在上面的基础上,做到复用。

            原型链+借用构造函数

 

  


 

        组合继承是JavaScript最常用的继承模式,但有些小问题,就是超类型在使用过程中会被调用2次,一次是创建子类型的时候,另一次是在子类型构造函数的内部。

 

寄生组合继承:

       

         解决了组合继承的2次调用的问题:

 

       


 


 


       最后再来一张图镇楼~~

        


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 32
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值