本章的主題是繼承,在javascript中要實現繼承比其他面相對象語言要複雜的多,他主要使用原型實現繼承。下面就介紹幾種常用的實現繼承的方式。
1.經典繼承(Classical Inheritance)
我們首先建立一個Person類。
/* Class Person. */function Person(name) { this.name = name;}Person.prototype.getName = function() { return this.name;}
現在我們建立一個Author類,繼承自Person
/* Class Author. */function Author(name, books) { //這種方式只能繼承Person建構函式內部的對象
Person.call(this, name); // Call the superclass's constructor in the scope of this.
this.books = books; // Add an attribute to Author.}
//將Author的prototype指向Person的執行個體,這樣他就繼承了Person prototype裡面的對象
Author.prototype = new Person(); // Set up the prototype chain.
//注意,要將Author的constructor重新指回他本身,因為指定原型之後,constructor已經為null,需要重新指定
Author.prototype.constructor = Author; // Set the constructor attribute to Author.Author.prototype.getBooks = function() { // Add a method to Author. return this.books;};
通過上面的步驟就實現了經典繼承,如果需要使用Author類,也是相當的簡單。
var author = [];author[0] = new Author('Dustin Diaz', ['JavaScript Design Patterns']);author[1] = new Author('Ross Harmes', ['JavaScript Design Patterns']);author[1].getName();author[1].getBooks();
當然我們可以通過一個擴充方法使繼承變的通用。
/* Extend function. */function extend(subClass, superClass) { var F = function() {}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass;}
現在整個繼承過程變為:
/* 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;}extend(Author, Person);Author.prototype.getBooks = function() { return this.books;};
2.原型繼承(Prototypal Inheritance)
經典繼承是通過聲明一個類的結構,通過初始化該類的執行個體來建立新對象。新對象包括自己單獨享有的屬性和與其他執行個體共用的方法。然而原型繼承並沒有類的建構函式,他只建立一個對象,然後他將自己以原型的方式提供給其他子類使用。下面我們來看例子:
/* Clone function. */
function clone(object) {
function F() {}
F.prototype = object;
return new F;
}
/* Person Prototype Object. */var Person = { name: 'default name', getName: function() { return this.name; }};
var reader = clone(Person);
alert(reader.getName()); // This will output 'default name'.
reader.name = 'John Smith';
alert(reader.getName()); // This will now output 'John Smith'.
Clone方法建立了一個新的空函數F,然後將F的prototype指向原型對象,最後函數返回F的執行個體。
比較經典繼承和原型繼承:
毫無疑問,經典繼承更容易理解,幾乎所有的javascript oop都是通過這種方式實現的。如果你建立一個廣泛使用的api,最好還是用這種方式。
原型繼承佔用更少的記憶體,因為所有的clone對象擁有同一份共用的屬性和方法集合,除非他們直接通過寫方法實現自己專屬的。