我们都知道,在JS中有一个function的东西。一般人们叫它函数。比如下面的代码
js代码:
function Person(name)
{
alert(name);
}
Person的表现的确跟一般的函数没有什么区别,接着看下面的代码
function Person(name)
{
this.name=name;
this.showMe=function()
{
alert(this.name);
}
};
var one=new Person('JavaScript');
one.showMe();//JavaScript
很多人见到了久违的new操作符,于是就叫Person为“类”,可是又没有关键字class的出现,觉得叫“类”有点勉强。于是退而求其次叫 Person为类的构造函数。
typeof Person;//"function"
typeof (new Person());//"object"
可以看出,没有new的Person就是一个函数
为了让javascript也面向对象,要在javascript中找到与传统面向对象语言的影子。可是按照javascript的说 法,function定义的这个Person就是一个Object(对象),而且还是一个很特殊的对象,这个使用function定义的对象与使用new 操作符生成的对象之间有一个重要的区别。这个区别就是function定义的任何函数都有一个prototype属性,使用new生成的对象就没有这个 prototype属性。
构造函数有一个prototype属性,prototype属性又指向了一个prototype对象
在 prototype对象中又有一个constructor属性,这个constructor属性同样指向一个constructor对象,而这个 constructor对象恰恰就是这个function函数本身。
![](http://hi.csdn.net/attachment/201010/20/0_12875687636Sip.gif)
证明如下:
alert("prototype" in Person);//true,prototype是Person的一个属性
typeof Person.prototype;//"object",prototype属性指向一个对象
但是:
(new Person()).prototype; //undefined ????此处有个疑问,prototype属性在Person中不是以this.prototype存在的,不然这里不会为undefined
"constructor" in Person.prototype;//true,prototype属性指向的prototype对象有一个constructor属性
Person.prototype.constructor===Person;//true,constructor属性指向function Person本身
在这里应该注意:constructor属性不影响任何JavaScript的内部属性。instanceof检测对象的原型链,通常你是无法修改的(不过某些引擎通过私有的__proto__属性暴露出来)。
constructor其实没有什么用处,只是JavaScript语言设计的历史遗留物。由于constructor属性是可以变更的,所以未必真的指向对象的构造函数,只是一个提示。不过,从编程习惯上,我们应该尽量让对象的constructor指向其构造函数,以维持这个惯例。
typeof Person.prototype.constructor;//"function"
我们接着看代码:
function Person(name)
{
this.name=name;
this.showMe=function()
{
alert(this.name);
}
};
Person.prototype.from=function()
{
alert('I come from prototype.');
}
var one=new Person('js');
one.showMe();//js,这个结果没有什么好奇怪的
one.from();//I come from prototype.,这个结果有一点奇怪吧
要解释这个结果就要仔细研究一下new这个操作符了.var one=new Person('js');这个语句执行的过程可以分成下面的语句:
var one={};
Person.call(one,'js');
按照《悟透javascript》书中说的,new形式创建对象的过程实际上可以分为三步:
A = new F();
第一步是建立一个新对象(A);
第二步将A的constructor属性置为F;
第三步将该对象(A)内置的原型对象(__proto__两个下划线)设置为构造函数(就是Person)prototype 属性引用的那个原型对象;
第四步就是将该对象(A)作为this 参数调用构造函数(就是Person),完成成员设置等初始化工作。
其中第二步中出现了一个新名词就是内置的原型对象,注意这个新名词跟prototype对象不是一回事,
cai=new Person("cai");
"prototype" in cai;//false
"__proto__" in cai;//true,说明对象A的内置原型对象为"__proto__"
cai.__proto__===Person.prototype;//这个内置的属性指向Person的prototype属性指向的那个原型对象。
为了区别我叫它inobj,inobj就指 向了函数Person的prototype对象。在Person的prototype对象中出现的任何属性或者函数都可以在cai对象中直接使用(真正意义上是被cai.__proto__使用),这个就 是javascript中的原型继承了。
![](http://hi.csdn.net/attachment/201010/20/0_1287568865k8zN.gif)
因为prototype对象中有一个constructor属性,那么one也可以直接访问constructor 属性。
代码:
Person.prototype.from=function()
{
alert('I come from prototype.');
}
var one=new Person('js');
one.showMe();//js,这个结果没有什么好奇怪的
one.from();//I come from prototype.,这个结果有一点奇怪吧
cai.__proto__.constructor===Person.prototype.constructor;//true
cai.constructor===Person.prototype.constructor;//true
接着看继承是如何实现的,继承的实现很简单,只需要把子类的prototype设置为父类的一个对象即可。注意这里说的可是对象哦!
那么通过prototype属性实现继承的原理是什么呢?还是先看图形说明,然后编写代码进行验证。
![](http://hi.csdn.net/attachment/201010/20/0_1287568921M6Zm.gif)
注意:红色的方框就是把子类与父类链接起来的地方。这个就应该是传说中的prototype链了吧。下面有代码进行验证。
js代码:
function SubPer(){ }
father=new Person("js");
SubPer.prototype=father;或
SubPer.prototype=new Person("js");//这句话的意思跟面向对象的语言一样的意义,比如java继承的时候在子对象的构造函数里一定要隐式或显式的调用父对象的构造函数来初始化父对象。
SubPer.prototype.constructor=SubPer; //SubPer的构造函数原先指的是SubPer,上一句执行以后SubPer.prototype指向了father,father.constructor=Person,因此SubPer.prototype.constructor=Person,因此要把构造函数换回来。
var son=new SubPer();
son.showMe();//js
son.from();//I come from prototype.
alert(father.constructor);//function SubPer(){...}//father已经是个实例了,因此它的构造器是哪个已经不重要了。
alert(son.constructor);//function SubPer(){...}
alert(SubPer.prototype.constructor);//function SubPer(){...}
SubPer的prototype指向father,那么son的__proto__指向father,son就可以调用一切father中的函数,而father可以调用Person.prototype里的所有函数,所以son可以调用Person.prototype里的所有函数,使用son.__proto__.__proto__.from(),__proto__省略掉。证明:
son.__proto__===father;//true
son.__proto__.__proto__===Person.prototype;//true