Javascript 面向对象详解

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


一:prototype和constructor

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

function People(name,age){
    this.name=name;
    this.age=age;
    this.getName=function(){
        return this.name;
    }
}

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

var a = new People('A',18);
var b = new People('B',19);
console.log(a.getName==b.getName);
输出结果为:false

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

People('C',20);
console.log(window.name);
console.log(window.getName());
程序输出结果:均为C

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

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

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

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

function People(name,age){
    this.name=name;
    this.age=age;
    
}
People.prototype.getName=function(){
        return this.name;
}

People.prototype.getAge=function(){
    return this.age;
}

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

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

  所以上面代码等价于:

function People(name,age){
    this.name=name;
    this.age=age;
    
}
People.prototype={
    getName:function(){
        return this.name;
        },
    getAge:function(){
        return this.age;
        }
};

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

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

var a = new People('A',18);
for(x in a )
 console.log(x.toString());
输出:

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

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

for(x in People.prototype)
   console.log(x.toString());
输出:

getName
getAge

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

function People(name,age){
    this.name=name;
    this.age=age;
    
}
People.prototype={
    id:'I am a People'
};
var a = new People('A',18);
var b = new People('B',19);
console.log(a.name==b.name);
console.log(a.id==b.id);
 
  输出结果: false  true

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

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

var aid=a.id
a.id="i am A";
console.log(b.id);
console.log(aid===b.id);
 程序输出:

I am a People
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属性的,测试如下:

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,构造函数代码修改如下:

function Boy(name,age,shape){
    People.call(this,name,age);
    this.shape=shape;
    for(f in People.prototype){
        Boy.prototype[f]=People.prototype[f];
    }
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值