Javascript 继承很复杂, 比其它任何面向对象语言都复杂. Javascript 是少数使用 原型式继承 的语言之一, 这也正是 Javascript 的优点.
继承主要分为两种: 类继承, 原型式继承.
代码重用, 易维护. 但是继承会增加对象之间的耦合度, 所以后面会讨论一些办法来对付它.
模拟类式继承, 先给出一个父类
/* Class Person. */ function Person(name) { this.name = name; } Person.prototype.getName = function(){ return this.name; }
(1) 原型链 ( 我们现在讨论的是 类式继承 )
创建一个继承 Person 的类 Author :
/* Class Author. */ function Author(name, books) { Person.call(this, name); // 1 this.books = books; // 2 } //------- 分割线 --------- Author.prototype = new Person(); // 3 Author.prototype.constructor = Author; // 4 Author.prototype.getBooks = function() { // 5 return this.books; }
上面的第1句好理解, 像在Java里一样, 调用父类的构造函数. 有点说头的就是3 , 4句. 我在这里多做些关于 constructor, obj.prototype and [[Prototype]] 的笔记.
function Author() { // some code goes here. }
下面分析一下 内置属性 [[Prototype]], obj.prototype, constructor 这三个东西
首先明确一下叫法, [[Prototype]]指向的对象叫做对象的原型对象, prototype指向的对象叫做 prototype对象. 为什么要分开, 因为上图也显示了这两个对象是不同的.
我们知道 Javascript 中, 每个对象都有 原型对象, 但每个对象却不一定有 prototype 属性, 如果没有 prototype 属性, 自然也就不存在 prototype对象.
只有函数对象才有 prototype 这个属性, 如上图的 Author() .
当定义 Author ( function Author() {} ) 后, 上图的链式结构就已经存在了. 请特别注意一下 Author.prototype 对象的 constructor 属性, 它现在已经存在了, 并且指回 Author 记住这个.
* [[Prototype]] , prototype 区别及作用?
- [[Prototype]]指明了当前对象( Author )的原型对象, 是和 Author 真正相关的东西.. [[Prototype]] = 我的构造的 prototype 属性的值.
- 仔细想一下第一条, 正好说明了 prototype 属性的作用, 这个属性是用来 初值化 由 Author 构造出来的实例的 [[Prototype]] 属性.
假如有:
var patrick = new Author();
那么 patrick 的 [[Prototype]] 的值就是 Author.prototype 的值. 所以说, Author.prototype 属性与 Author 类更加息息相关, 为了好理解, 说的极端点 Author.prototype 是为其实例服务的, 和 Author 类本身关系不大.
// 创建一个实例 var patrick = new Author();
--------------- 回到上面话题 ---------------
/* Class Author. */ function Author(name, books) { Person.call(this, name); // 1 this.books = books; // 2 } //------- 分割线 --------- Author.prototype = new Person(); // 3 Author.prototype.constructor = Author; // 4 Author.prototype.getBooks = function() { // 5 return this.books; }
* 为什么 constructor 会变?
- 像第一个图里那样, constructor 是在创建Author类的时候在Author.prototype上自动创建的属性并指回Author. 当后来手动改变了Author.prototype = new Person() 后. 这时的
constructor 是什么? 假设new 出来的Person 为 p. 那么 查找 p.constructor , 在 p 里没有此属性, 沿着原型链往上找, p 的原型是 Person.prototype , 这里有 constructor 属性, 但是它的值是指向 Person() 构造函数. 所以要上面代码的第4句, 手动设置回成Author.
下一话题.
(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(); }