• Javascript 面向对象详解-转


    转自:http://blog.csdn.net/yueguanghaidao/article/details/9747033

    刚接触Js的童鞋会很不习惯Js的prototype继承,不管是C++,Java,还是Python 都有完整的类继承机制,如果把以前的思路带到Js中,你会吃不少的亏,所以我们首先要做的就是转换思路,将Js的继承机制当作新的东西学习,也不要疑惑为啥Js的继承这么麻烦,为什么没有Class的支持呢?统统的一切疑惑你都要换个思路,如果你最早接触的开发语言是Js,当你再遇到C++时,你也会有一样的疑惑,所以告诉自己人家就是这么实现的,Just do it。

    一:prototype和constructor

    首先看一下下面的代码(全部Js代码均可在firebug控制台中运行)

    1 function People(name,age){
    2     this.name=name;
    3     this.age=age;
    4     this.getName=function(){
    5         return this.name;
    6     }
    7 }

    我想大家想象的类应该这么写,可这么写我们会发现getName这个函数和name变量一样,也就是新建的每一个对象都要定义这个函数,貌似有点浪费资源,有下为证:

    1 var a = new People('A',18);
    2 var b = new People('B',19);
    3 console.log(a.getName==b.getName);

    输出结果为:false

       你说Js也真是的,不提供class支持也就罢了,成员函数还不可以写在构造函数中,啥你说构造函数,是的,function People就是People类的构造函数。其实和一般函数没有区别,我们也可以直接运行。

    1 People('C',20);
    2 console.log(window.name);
    3 console.log(window.getName());

    程序输出结果:均为C

       由于我们是直接调用的,所以this没有指定,那么默认就是全局的window对象。

       而且对象的构造函数我们是可以得到引用的,

    console.log(a.constructor==b.constructor);输出的结果是:true,

      那我们在Js中应该怎么写类呢?这就涉及到Js独特的prototype了。

     1 function People(name,age){
     2     this.name=name;
     3     this.age=age;
     4     
     5 }
     6 People.prototype.getName=function(){
     7         return this.name;
     8 }
     9 
    10 People.prototype.getAge=function(){
    11     return this.age;
    12 }

    prototype是每一个类都有的一个属性,这个属性说白了就是一个对象,那么对象肯定是有属性的,你new的每一个对象都将拥有该对象的所有属性。

    那么如果自己定义类的prototype对象,也就实现了我们给类定义成员函数的目的。

      所以上面代码等价于:

     1 function People(name,age){
     2     this.name=name;
     3     this.age=age;
     4     
     5 }
     6 People.prototype={
     7     getName:function(){
     8         return this.name;
     9         },
    10     getAge:function(){
    11         return this.age;
    12         }
    13 };

    现在我们都懂了,原来只要在类的prototype属性中设置任何我们想要的,实例化后的每个对象都将拥有该属性,多么完美啊。

     我们看看实例后的对象是否拥有这些方法:

    1 var a = new People('A',18);
    2 for(x in a )
    3  console.log(x.toString());

    输出:

    name
    age
    getName
    getAge
    果然,实例后的对象都拥有prototype对象拥有的属性。
     

    既然People.prototype也是对象,那么我们应该也可以将它的属性打出来。

    1 for(x in People.prototype)
    2    console.log(x.toString());

    输出:

    getName
    getAge

    那又怎能确定是引用prototype的属性而不是复制呢?

     1 function People(name,age){
     2     this.name=name;
     3     this.age=age;
     4     
     5 }
     6 People.prototype={
     7     id:'I am a People'
     8 };
     9 var a = new People('A',18);
    10 var b = new People('B',19);
    11 console.log(a.name==b.name);
    12 console.log(a.id==b.id);

    输出结果: false  true

      从上面我们可以看出,的确使用的是引用。

      那我要修改a.id怎么办,b.id会变吗?想想如果你是设计人员,你会怎么做?

    1 var aid=a.id
    2 a.id="i am A";
    3 console.log(b.id);
    4 console.log(aid===b.id);

    程序输出:

    I am a People      true

      正如你所想的,肯定将重新绑定a.id了。

      到这里其实大家对单实例的prototype肯定都没有问题了,这里还需要扩展一下constructor属性。

      其实,通过(1)People.prototype.getName=function(){}:和(2)People.prototype={};还是有一点区别,区别就在于prototype是否丢弃了constructor属性的引用。

    对象的实例和prototype都拥有constructor属性(构造函数的引用)

      通过(1),People.protorype是由constructor属性的,测试如下:

    1 console.log(People.prototyp.constructor===People);

    将会输出true

    而通过(2)将会输出:false。

    二:继承

     看到这里肯定对prototype熟悉了,那么继承就非常简单了。

    function People(name,age){
        this.name=name;
        this.age=age;
        
    }
    People.prototype={
        getName:function(){
            return this.name;
            },
        getAge:function(){
            return this.age;
            }
    };
    
    function Boy(name,age,shape){
        People.call(this,name,age);
        this.shape=shape;
    }
    Boy.prototype=People.prototype;
    Boy.prototype.getShape=function(){
        return this.shape;
    };
    
    var boy=new Boy('kitty',6,"fat");
    console.log(boy.getName());
    console.log(boy.getShape());

    Boy类继承People类,所以最简单的就是让Boy的prototype等于People的prototype,这样Boy将拥有People.prototype的所有属性,最后再添加自己需要的成员函数即可。

    其实我们也可以在Boy的构造函数中将People.prototype的所有属性添加到Boy.prototype,构造函数代码修改如下:

    1 function Boy(name,age,shape){
    2     People.call(this,name,age);
    3     this.shape=shape;
    4     for(f in People.prototype){
    5         Boy.prototype[f]=People.prototype[f];
    6     }
    7 }
  • 相关阅读:
    matplotlib-2D绘图库-面向对象
    C 指针
    POCO库中文编程参考指南(8)丰富的Socket编程
    POCO C++ SOCKET
    c++ poco StreamSocket tcpclient测试用例
    用OpenLayers开发地图应用
    Nginx-rtmp模块实现流媒体play、push、pull功能
    使用pjsip传输已经编码的视频,源码在github
    ReSIProcate源码目录下功能说明
    resiprocate使用入门:内网搭建基于repro的sipproxy测试环境
  • 原文地址:https://www.cnblogs.com/johnnylion/p/4107370.html
Copyright © 2020-2023  润新知