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 }

 

posted @ 2014-11-19 08:55  johnnylion  阅读(127)  评论(0编辑  收藏  举报