JavaScript 继承
我们用继承来减少重复性代码,并尽量弱化对象间的耦合。
1.类式继承
JavaScript可以被装扮成使用类式继承的语言。通过用函数来声明类,用关键字new来创建实例。下面是JavaScript中一个简单的类声明。
function Person(name) { this.name = name; } Person.prototype.getName = function() { return this.name; }; var reader = new Person("Alice"); reader.getName(); /*你可以访问所有实例的属性,也可以调用所有实例的方法。*/
1)原型链
创建一个类Author,来继承Person。
function Person(name) { this.name = name; } Person.prototype.getName = function() { return this.name; }; var reader = new Person("Alice"); reader.getName(); /*你可以访问所有实例的属性,也可以调用所有实例的方法。*/ function Author(name, books) { //Call the superclass's constructor in the scope of this Person.call(this, name); this.books = books; } Author.prototype = new Person(); Author.prototype.constructor = Author; Author.prototype.getBooks = function() { return this.books; } var author = []; author[0] = new Author('Alice', ['C++', 'c#']); author[1] = new Author('Bill', ['Java', 'JavaScript']); console.log("姓名" + author[0].getName() + " 书籍" + author[0].getBooks()); console.log("姓名" + author[1].getName() + " 书籍" + author[1].getBooks());
为了让Author继承Person,必须手工将Author的prototype设置为Person的一个实例。最后一个步骤是将prototype属性重设为Author.这意味着为了让一个类继承另一个类,只需将子类的prototype设置为指向超累的一个实例即可。
2) extend 函数
为了简化类的声明,可以把派生子类的整个过程包装在一个名为extend的函数中。它的作用于其他语言中的extend关键字类型,即基于一个给定的类结构创建一个新的类。
/* Extend function*/ function extend(subClass, superClass) { var F = function() {}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; subClass.superClass = superClass.prototype; if (superClass.prototype.constructor == Object.prototype.constructor) { superClass.prototype.constructor = superClass; } } function Author(name, books) { Author.superClass.constructor.call(this, name); this.books = books; } extend(Author, Person); Author.prototype.getBooks = function() { return this.books; }; Author.prototype.getName = function() { var name = Author.superClass.getName.call(this); return name + ',Author of' + this.getBooks().join(','); }
2.原型式继承
使用原型式继承时,并不需要用类来定义对象的结构,只需直接创建一个对象即可。这个对象随后可以被新的对象重用,这得益于原型链查询的工作机制。该对象被称为原型对象,这是因为它为其他对象应有的模样提供了一个原型。
var Person = { name: 'default name', getName: function() { return this.name; } }; var reader = clone(Person); alert(reader.getName()); reader.name = 'Alice'; alert(reader.getName()); var Author = clone(Person); Author.books = []; Author.getBooks = function() { return this.books; } var author = []; author[0] = clone(Author); author[0].name = 'Alice'; author[0].books = ['C++', 'C#']; author[0] = clone(Author); author[0].name = 'Bill'; author[0].books = ['Java', 'JavaScript']; function test() { return '姓名:' + author[0].getName() + ' 书籍:' + author[0].getBooks().join(','); }
这里并没有使用一个名为Person的构造函数来定义类的结构,Person现在是一个对象字面量。clone函数可以用来创建新的类Person对象。他会创建一个空对象,而该对象的原型对象被设置成为Person。这意味着在这个新对象中查找某个方法或属性时,如果找不到,那么查找过程会在其原型对象中继续进行。
clone函数详解
/* Clone function function clone(object){ function F(); F.prototype=object; return new F; // new F相当于new F(); } */