javascript中的继承
向所有的面向对象语言一样,js也拥有继承特性,然而不像大多数OO(Object-Oriented)语言一样,JS只有实现继承,没有接口继承。那么,原型链便起到了决定性的作用。
在ECMAScript中,原型链是实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。其关键步骤便是让一个函数的原型对象成为另一个函数的实例。(理解可能有错,欢迎指正,一起学习)。
以下段代码来理解
function GrandFather(){ this.frandFatherProperty=true; } GrandFather.prototype={ first_name:"guo", hair_color:"red", }; function Parent(){ this.parentProperty=false; } Parent.prototype=new GrandFather(); Parent.prototype.city="zhengzhou";
var boy=new Parent();
alert(boy.city); //zhengzhou alert(boy.parentProperty); //false alert(boy.first_name); //guo
上段代码定义了两个类型,GrandFather,Parent,当使用Parent.prototype=new GrandFather()时,也就意味着创建一个GrandFather类型的实例保存在Parent.prototype中,此时Parent的原型中生成了一个内部指针指向GrandFather的原型,此时Parent的原型为实例对象,所以Parent.prototype也包含了一个实例属性frandFatherProperty.一次类推,boy便继承了Parent的属型。这也是原型链的工作机制,其本质时款占了原型搜索机制,自实例向外部查询,也就是向上查询。当然,默认的一环也是不能忽略的,也就是Object.prototype,就是说所有函数均继承自Object.
我们需要注意的是,必须在原型的实例替换掉原型后,再为原型的属型添加或者重写方法。如上Parent.prototype=new GrandFather()在Parent.prototype.city=..之前定义。还有就是不能通过字面量表示法创建原型方法,否则会导致重写原型链。
既然可以通过对自定义类型的实例的属性(与原型对象的属性重名)的修改达到屏蔽原型对象属性目的,那么继承也可以,因为其本质上也是实例化。但需要注意的是,重写的方法不会影响原型对象。
原型链继承的过程中还有一个要注意的就是引用类型的使用了,类似于上一节将的引用类型效果,在继承中有人会出现这样的问题,基石混合模式也无济于事,因为在继承的过程中原型对象(替换成了实例)拥有了独立的属性,而不再是实例属性。那么,如何解决呢?可以使用组合继承,通过构造函数技术来继承实例属性,通过原型链来继承原型属性。
function Person(first_name) { this.first_name=first_name; this.friends=["Mike","John"]; } Person.prototype.city="zhengzhou"; function Parent(first_name,age){ Person.call(this,first_name); this.age=age; } Parent.prototype=new Person(); Parent.prototype.constructor=Parent; Parent.prototype.cat=function () { alert("hello"); } var son=new Parent("guo",20); var girl=new Parent("guo",21); son.friends.push("AEE"); girl.friends.push("G"); alert(son.friends); //Mike,John,AEE alert(son.first_name); //guo alert(girl.friends); //Mike,John,G alert(girl.first_name); //guo
此外,ECMAScript5有支撑了另外一种原型式继承的写法Object.create().其参数为一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。