原型继承是JavaScript中另一个让像我这样的初学者困惑的特性。JavaScript有一个无类型的(class-free)对象系统,在这个系统中,对象直接从其他对象中继承属性。《JavaScript语言精粹》中提到这是一个非常强大的特性。
但是对于我们这种习惯在Java里那样通过使用“类”来构造对象的初学者来说,原型继承是一个非常陌生的概念。
在Java里,继承提供的一个非常重要的服务是,它提供了代码复用的一种形式。如果一个我们正在构造的类和一个已经存在的类的大部分属性相同,就像是兄弟姐妹那样的关系的话,那我们只需要说明他们之间的不同点即可,比如:性别的不同,年龄的不同…等,而我们之间相同的属性则不必特地说明,比如:我们住在相同的地方,我们拥有同样的父母…等。
这是一个非常容易理解的子类继承父类的例子。
可是在JavaScript中,没有“父类”与“子类”这样的概念,还记得吗?在上一篇博客中我们提到JavaScript是一门弱类型的语言,弱类型的特性在这里也有体现,JavaScript不需要类型转换,对它来说,一个对象的继承关系是无关紧要的,对于一个对象最重要的是它能做什么,而不是它从哪里来。
那么在JavaScript中的继承机制——原型继承,到底是怎么实现的呢,下面列出了我的一些初步的想法。
Java中使用”new“命令生成一个实例对象
Cat xiaohei=new Cat();
JavaScript中没有“类”,但是有“new”这个关键字。
JavaScript中直接从原型对象通过使用“new"命令生成一个实例对象,但是没有”类“的JavaScript怎么表达”原型对象“这个概念呢,答案是通过构造函数。"new"命令后面紧接着的不是 “类"而是“构造函数”.
举个栗子,现在有一个叫做Cat的构造函数,表示”猫“对象的原型。
function Cat(name){
this.Name=name;
}
对这个构造函数使用"new"命令,就会生成一个”猫“对象的实例对象。
var XiaoHei=new Cat("小黑");
构造函数中的"this"关键字,就代表了新创建的实例对象.
好了,现在实现了”构造一个实例对象“这个工作,如何实现”继承“呢?
用构造函数生成一个实例对象,是无法共享属性和方法的,而这些属性和方法就是我们在Java里放在父类里的属性和方法。
举个栗子:
在Cat对象的构造函数中,设置一个实例对象的共有属性"TheNumberOfLegs"(腿的数量)
function Cat(name){
this.Name=name;
this.TheNumberOfLegs=4;
}
然后生成两个实例对象
var XiaoHei= new Cat("小黑");
var XiaoBai=new Cat("小白");
这两个实例对象的”TheNumberOfLegs“属性是相互独立的,修改一个并不会影响另一个
XiaoHei.TheNumberOfLegs=3;
alert(XiaoBai.TheNumberOfLegs);//显示"4",并不受XiaoHei的影响。
为了解决这个问题,JavaScript引入了"prototype"这个属性。
这个属性到底是个什么东西我们暂且不谈,因为我也没搞懂。我们现在暂时把它理解为一个“公用的存储空间”对象好了。
所有实例对象需要共享的属性和方法都可以放在这个空间里,那些不要共享的属性和方法就放在构造函数里。
function Cat(name){
this.name=name;
}
Cat.prototype={TheNumberOfLegs:4};
var XiaoHei=new Cat("小黑");
var XiaoBai=new Cat("小白");
alert(XiaoHei.TheNumberOfLegs);//4
alert(XiaoBai.TheNumberOfLegs);//4
Cat.prototype.TheNumberOfLegs=3;
alert(XiaoHei.TheNumberOfLegs);//3
alert(XiaoBai.TheNumberOfLegs);//3
现在TheNumberOfLegs属性放在“共有存储空间里”对象里,是两个是实例对象共享的,只要修改了这个值,两个实例对象都会受到影响。
由于所有实例对象共享一个“共有存储空间”对象,从外界看起来,这个“共有存储空间”对象就是实例对象的原型,而实例对象则继承了这个原型“共有存储空间”对象。
有关于原型继承,还有很多需要继续深入的地方,特别是有关prototype属性,是JavaScript学习中的一个难点。
更多内容请参考:这个链接
Ps:这个链接也是转载的文章,文章的出处没有找到…