Javascript语言的继承机制一直很难被人理解。
它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(prototype chain)模式,来实现继承。
Brendan Eich设计javascript之初是为了实现网页与浏览器之间交互的一种简单的脚本语言
如果真的是一种简易的脚本语言,其实不需要有"继承"机制。但是,Javascript里面都是对象,必须有一种机制,将所有对象联系起来。所以,Brendan Eich最后还是设计了"继承"。
javascript实现继承的方式
C++和Java语言都使用new命令,生成实例。
C++
ClassName*object=new ClassName(param);
java
Foo foo=new Foo();
JavaScript引入了new命令,但由于它没有"类"的概念。考虑到C++和Java使用new命令时,都会调用"类"的构造函数(constructor)。于是,Brendan Eich在设计JavaScript时做了一个简化,new命令后面跟的不是类,而是构造函数。
构造函数和prototype对象之间的关系
function DOG(name){
this.name=name;
this.species='犬科';
}
var dogA=new DOG('大毛');
var dogB=new DOG('二毛');
dogA.species='猫科';
alert(dogB.species);// 显示"犬科
用构造函数生成的每一个实例对象都有自己的属性和方法的副本,这不仅无法做到数据共享,也是极大的资源浪费。
考虑到这一点,Brendan Eich为构造函数设置一个prototype属性。这个属性包含一个对象(以下简称"prototype对象")
prototype对象和实例对象的关系
function DOG(name){
this.name=name;
}
DOG.prototype={
species:'犬科'
};
var dogA=new DOG('大毛');
var dogB=new DOG('二毛');
alert(dogA.species);// 犬科
alert(dogB.species);// 犬科
实例对象的属性和方法继承prototype对象
实例对象的_proto_属性的值就是它所对应的原型对象
当你创建函数时,JS会为这个函数自动添加prototype属性,值是空对象。而一旦你把这个函数当作构造函数(constructor)调用(即通过new关键字调用),那么JS就会帮你创建该构造函数的实例,实例继承构造函数prototype的所有属性和方法(实例通过设置自己的__proto__指向承构造函数的prototype来实现这种继承)。
若想访问一个对象的原型,应该使用什么方法?
1、使用_proto_属性
每个JS对象一定对应一个原型对象,并从原型对象继承属性和方法。
对象__proto__属性的值就是它所对应的原型对象;
function DOG(name){
this.name=name;
}
DOG.prototype={
species:'犬科'
};
var dogA = new DOG('大毛');
var dog B = new DOG('二毛');
dogA.__proto__==DOG.prototype;//true
dogB.__proto__==DOG.prototype;//true
对象的__proto__指向自己构造函数的prototype。obj.__proto__.__proto__...的原型链由此产生,包括我们的操作符instanceof正是通过探测obj.__proto__.__proto__... === Constructor.prototype来验证obj是否是Constructor的实例。
2、使用Object.getPrototypeOf()
Object.getPrototypeOf(dogA)==DOG.prototype;//true
Object.getPrototypeOf(dogB)==DOG.prototype;//true
使用__proto__是有争议的,而且是不鼓励的。 它从来没有被包括在EcmaScript语言规范中,但是现代浏览器实现了它, 无论如何。__proto__属性已在ECMAScript 6语言规范中标准化,用于确保Web浏览器的兼容性,因此它未来将被支持。它已被不推荐使用, 赞成使用Object.getPrototypeOf。
我们知道JS是单继承的,Object.prototype是原型链的顶端,所有对象从它继承了包括toString等等方法和属性。
Object本身是构造函数,继承了Function.prototype;Function也是对象,继承了Object.prototype。这里就有一个_鸡和蛋_的问题:
Object instanceof Function// true
Function instanceof Object// true
Function本身就是函数,Function.__proto__是标准的内置对象Function.prototype。
Function.prototype.__proto__是标准的内置对象Object.prototype。
参考文献: