1、简介
??????在JS中继承是一个非常复杂的话题,比其他任何面向对象语言中的继承都复杂得多。在大多数其他面向对象语言中,继承一个类只需使用一个关键字即可。在JS中想要达到继承公用成员的目的,需要采取一系列措施。JS属于原型式继承,得益于这种灵活性,我们既可以使用标准的基于类的继承,也可以使用更微妙一些的原型式继承。在JS中应该要明确一点,一切继承都是通过prototype来进行的,且JS是基于对象来继承的。
2、最直观的继承方式
??????我们假设现在有这么一个继承层次:一个Person基类,含有name属性和一个getName方法;一个Author类,继承了Person类,有着特有的books属性和getBooks方法。最简单的类式继承方法如下:
[javascript] view plaincopy
????/*Class Person*/ 
????function Person(name){ 
????????this.name = name; 
????} 
??????
????Person.prototype.getName = function(){ 
????????????return this.name; 
????}; 
??????
????/*Class Author*/ 
????function Author(name, books){ 
????????Person.call(this, name); //调用父类构造函数,第二次调用父类构造函数 
????????this.books = books; 
????} 
??????
????Author.prototype = new Person(); //设置原型链以获得父类的方法, 第一次调用父类构造函数 
????Author.prototype.constructor = Author; //设置构造函数 
????Author.prototype.getBooks = function(){ 
????????return this.books; 
????}; 
上述代码的不足之处在于:实例化Authro对象时,将会2次调用父类的构造函数,且需要额外的保存原型链中实例化父类的对象,上述代码就保存了父类中的一份name属性,事实上这是不必要的。 如果继承层次多些,属性也多些,这个造成的负担就大了。 我们可以对此进行改进,事实上,我们需要的只是父类的原型上的东西,那些父类包含的属性通过调用父类构造函数已经获得了。另外,上述代码看起来似乎父类和子类的关联性不大,因此在这里,我们给函数原型增加一个extend函数,以明确表明继承层次,于是有了下面的原型式继承。
?3、原型式继承
???????谈到原型式继承时,最好忘掉自己关于类和实例的一切知识,只从对象的角度来思考。 前面我们说到,JS是基于对象来继承的,对象的prototype属性实质也是指向一个实例化的对象。因此,我们可以想到,并不需要用类(构造函数)来定义对象的结构,只需直接创建一个对象即可。请看下面的代码:
[javascript] view plaincopy
????/*extend函数,实现原型式继承*/ 
????var extend = function(obj){ 
????????if(typeof obj !== 'object'){ 
????????????throw new Error('fatal error: "Object.prototype.extend" expects a object'); 
????????} 
??????????
????????var F = function(){}; //创建一个中间函数对象 
????????F.prototype = obj; //设置其原型对象指向obj 
??????????
????????return new F();//返回实例化的F 
????}; 
??????
????/*父类字面量对象*/ 
????var Person = { 
????????init: function(name){ //初始化函数,进行各种属性设置,代替了构造函数的作用 
????????????this.name = name; 
????????}, 
????????getName:function(){ 
????????????return this.name; 
????????} 
????}; 
??????
????/*子类对象*/ 
????var author1 = extend(Person); //继承Person 
                        
                    
