类式继承
function Person(name){ this.name = name; } Person.prototype.getName = function(){ return this.name; }
要创建该类的实例,只需要结合关键字new调用这个构造函数即可:
var reader = new Person('Bob'); reader.getName();
原型链
创建继承Person的类则要复杂一些:
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; };
首先要做的是创建一个构造函数,在构造函数中,调用超类的构造函数,并将name参数传给它。
在使用new运算符的时候,系统会为你做一些事。它先创建一个空对象,然后调用构造函数,在此过程中这个空对象处于作用域链的最前端。而在Author函数中调用超类的构造函数时,你必须手工完成同样的任务。"Person.call(this, name)" 这条语句调用了Person的构造函数,并且在此过程中让那个空对象(用this代表)处于作用域链的最前端,而name则被作为参数传入。
为了让Author继承Person,必须手工将Author的prototype设置为Person的一个实例。最后一个步骤是将prototype的constructor属性重设为Author(因为把prototype属性设置为Person的实例时,其constructor属性被抹除了)。
extend函数
为了简化类的声明,可以把派生子类的整个过程包装在一个名为extend的函数中。它的作用于其他语言的extend关键字类似,即基于一个给定的类结构创建一个新的类:
function extend(subClass, superClass){ var F = function() {}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; }
这个函数添加了一个空函数F,并用它创建的一个对象实例插入原型链中。这样做可以避免创建超类的新实例,因为它可能会比较庞大,而且有时超类的构造函数会有一些副作用,或者会执行一些需要进行大量计算的任务。
原型式继承
var Person = { name: 'Bob', getName: function(){ return this.name; } };
Person现在是一个对象字面量。它是所要创建的其他各种类Person对象的原型对象。
function clone(object){ function F() {} F.prototype = object; return new F; }
clone函数首先创建了一个新的空函数F,然后将F的prototype属性设置为作为参数object传入的原型对象。prototype属性就是用来指向原型对象的,通过原型链接机制,它提供了到所有继承而来的成员的链接。该函数最后通过把new运算符作用于F创建出一个新对象,然后把这个新对象作为返回值返回。函数所返回的这个克隆结果是一个以给定对象为原型对象的空对象。
var reader = clone(Person); reader.getName(); // Bob reader.name = 'John'; reader.getName(); // John
clone函数可以用来创建新的类Person对象。它会创建一个空对象,而该对象的原型对象被设置成Person。这意味着在这个新对象中查找某个方法或属性时,如果找不到,那么查找过程会在其原型对象中继续进行。
var Author = clone(Person); Author.books = []; Author.getBooks = function (){ return this.books; }
不必为创建Author而定义一个Person的子类,只要执行一次克隆即可
用工厂的方式来创建一个childObject
var CompoundObject = {}; CompoundObject.string1 = 'default value'; CompoundObject.createChildObject = function(){ return { bool: true, num: 10 } }; CompoundObject.childObject = CompoundObject.createChildObject(); var compoindObjectClone = clone(CompoundObject); compoindObjectClone.childObject = CompoundObject.createChildObject(); compoindObjectClone.childObject.num = 5;
继承的适用场合
继承会使代码变得更加复杂、更难被理解,所以只应该用在其带来的好处胜过缺点的那些场合。它的主要好处表现在代码的重用方面。通过建立类或对象之间的继承关系,有些方法我们只需要定义一次即可。