javascript设计模式--继承(下)
本章的主题是继承,在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对象拥有同一份共享的属性和方法集合,除非他们直接通过写方法实现自己独有的。