上一篇博客說到了node.js繼承events類實現事件發射和事件綁定函數,其中咱們實現了一個公用基類 _base ,而後在模型中差別化的定義了各類業務須要的模型並繼承 _base 公共基類.可是其中的繼承是一筆帶過,今天詳細的說下node.js中繼承.javascript
var events=require('events'); var util=require('util'); function _base(){ this.emitter=new events.EventEmitter(this); }; util.inherits(_base,events.EventEmitter); //繼承 _base.prototype.onEvent=function(eventName,callback){ this.emitter.on(eventName,callback); } _base.prototype.emitEvent=function(eventName,arg){ this.emitter.emit(eventName,arg); } module.exports=_base;
util 包介紹:html
node.js中的util核心包是node.js自帶的核心代碼,其徹底用javascript代碼實現,裏面實現了一些經常使用的工具方法.java
其中,咱們今天要說的繼承方法 inherites 就是util 核心包實現的一個api node
util.inherits :api
util.inherits(constructor, superConstructor)
此方法有2個參數: 此方法參數針對的都是構造函數bash
constructor : 構造函數函數
superConstructor: 父類構造函數工具
分析最上面的代碼:ui
var events=require('events'); var util=require('util');
node.js 核心代碼都包含上面的2個包,直接 require 引用便可this
接下來是構造函數:
function _base(){ this.emitter=new events.EventEmitter(this); };
此構造函數裏定義了一個私有變量 emitter ,細心的人應該發現此私有變量在下面的方法中用到了,爲何會這樣,咱們會再下一篇博客中來分析原型對象爲什麼能共享構造函數中的私有變量.(此篇略過)
再下來是繼承語法:
util.inherits(_base,events.EventEmitter); //繼承
inherits 把2個構造函數傳入進去到底作了什麼?
咱們來看下 inherits 的源碼:
exports.inherits = function(ctor, superCtor) { ctor.super_ = superCtor; ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }); };
在上面的代碼中 ctor 想要繼承 superCtor ,咱們姑且把 ctor 稱做子類, superCtor 稱做父類.
ctor.super_= superCtor;
super_屬性是子類繼承父類時構造函數要寫入的一個屬性值.
ctor.prototype=Object.create(superCtor,prototype,{.....});
咱們能夠看到源碼中子類原型指像父類原型對象.
當經過 new關鍵字建立子類對象時,子類原型對象上的屬性都將會複製一份到子類對象中.就這樣達到了繼承的效果.
上面子類原型被Object.create() 方法賦值,那麼咱們再來看下 Object,create 是何方神聖.
Object.create
Object.create(proto [, propertiesObject ])
做用:
經過指定的原型對象和屬性建立一個新的對象.
proto 就是原型對象,
propertiesObject 就是指定的原型對象的屬性,可選屬性(非必填),如何理解這個參數? 它有4個屬性,以下:
var myBlog = Object.create({}, {'blog':{'value':'yijiebuyi', 'writable': false, 'enumerable': false, 'configurable': false}});
咱們定義了一個 myBlog 對象引用
經過 Object,create 來賦值, 原型對象爲 {}
propertiesObject 是對應的
{'blog':{'value':'yijiebuyi', 'writable': false, 'enumerable': false, 'configurable': false}}
value: 表示blog 的屬性值; writable: 表示blog 的屬性值是否可寫;[默認爲: false] enumerable: 表示屬性blog 是否能夠被枚舉;[默認爲: false] configurable: 表示屬性blog 是否能夠被配置,例如 對obj.a作 delete操做是否容許;[默認爲: false]
因此:create 函數實現原理就是 指定一個原型對象 obj ,而後把指定屬性(及屬性的配置)指到 原型對象下.
那麼最後獲得的 myblog 對象是這樣的 {blog: "yijiebuyi"}
那咱們知道了 util 中的 inherits 方法內部主要是調用了 Object.create來建立了一個新對象,新對象是基於父類原型對象 superCtor.prototype
另一個屬性是 constructor ,構造函數new出來的對象都有此屬性,此屬性值是指向了構造函數的引用.咱們通常經過此屬性能夠得知這個對象是被誰new出來的.
{ constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }
如上代碼就是定義了 contructor 屬性,它的值是 ctor ,ctor是什麼? 別忘了咱們的初衷, ctor正是 inherits 函數傳入的第一個參數,就是子類引用.
因此這個 create 函數建立了一個以父類原型對象爲基礎的新對象,同時把 contructor 屬性指向子類構造函數.