express源碼中的對象繼承
nodejs web框架express
源碼中, 多處封裝涉及到了對象繼承,單獨拿出來總結下它們的特點,參考學習
對象繼承方式
簡單閱讀源碼所看到的對象繼承方式有三種形式
- merge-descriptors
var EventEmitter = require(events).EventEmitter;var mixin = require(merge-descriptors);//app對象從EventEmitter.prototype對象繼承mixin(app, EventEmitter.prototype, false);
- Object.create()
//app.request對象從req對象繼承,並定義app屬性app.request = Object.create(req, { app: { configurable: true, enumerable: true, writable: true, value: app } })
- Object.setPrototypeOf()
var setPrototypeOf = require(setprototypeof)//將router對象的原型對象設置為protosetPrototypeOf(router, proto)
源碼分析
這應該是最常用的的幾種繼承形式了
屬性拷貝
第一種為屬性值拷貝,沒什麼技巧就是把要繼承的屬性全部拷貝到自己身上, 可以選擇是否覆蓋同名屬性
源碼的實現如下
//merge-descriptorsmodule.exports = mergevar hasOwnProperty = Object.prototype.hasOwnProperty/** * Merge the property descriptors of `src` into `dest` * * @param {object} dest Object to add descriptors to * @param {object} src Object to clone descriptors from * @param {boolean} [redefine=true] Redefine `dest` properties with `src` properties * @returns {object} Reference to dest * @public */function merge(dest, src, redefine) { if (!dest) { throw new TypeError(argument dest is required) } if (!src) { throw new TypeError(argument src is required) } if (redefine === undefined) { // Default to true redefine = true } Object.getOwnPropertyNames(src).forEach(function forEachOwnPropertyName(name) { if (!redefine && hasOwnProperty.call(dest, name)) { // Skip desriptor return } // Copy descriptor var descriptor = Object.getOwnPropertyDescriptor(src, name) Object.defineProperty(dest, name, descriptor) }) return dest}
拷貝繼承,繼承時會耗費更多時間和空間,但後續訪問時理論上效率更高
常駐於內存中的對象更加適合這種繼承方式, 一次繼承多次使用
後兩種可歸為一類,均是從原型對象繼承
原型繼承
原型繼承,是js中常見的的繼承方式,這裡有用到了兩種操作方法
Object.create(proto[, propertiesObject])
返回在指定原型對象上添加新屬性後的對象
即除了繼承之外,還可以自定義屬性setprototypeof
//setprototypeofmodule.exports = Object.setPrototypeOf || ({__proto__:[]} instanceof Array ? setProtoOf : mixinProperties);function setProtoOf(obj, proto) { obj.__proto__ = proto; return obj;}function mixinProperties(obj, proto) { for (var prop in proto) { if (!obj.hasOwnProperty(prop)) { obj[prop] = proto[prop]; } } return obj;}
一般來說調用的是原生介面Object.setPrototypeOf
同時也提供了兩種兼容方案
obj.__proto__ = proto;
- 屬性值拷貝
總結
自己寫代碼或者寫庫程序不可避免會涉及到繼承封裝,express提供了久經考驗的最佳實踐
- 對於常駐對象推薦使用
屬性拷貝
,用空間換時間 - 原型繼承有
Object.create()
和Object.setPrototypeOf()
等方法,分別有各自適合的場景,更多了解可以參照MDN的說明 - 不想自己造輪子,express的這倆輪子也可以直接拿來使用,
merge-descriptors
和setPrototypeOf
, 源碼也十分簡潔
推薦閱讀: