Underscore源碼解析
前言
Underscore是一個JavaScript工具庫,它提供了許多操作集合、數組、函數等的實用函數。簡單說它集成了好多工具函數,不用自己寫一些常用的函數了。
準備
軟件 | 描述 |
---|---|
git | 代碼管理工具 |
步驟
克隆代碼到本地:
git clone https://github.com/jashkenas/underscore.git
查看目錄結構:
從目錄結構中可以看到,只有一個docs(文檔)和test(測試)目錄,然後看下根目錄下,可以推測源碼文件就一個underscore.js文件(min文件是壓縮文件)
查看package.json文件(TODO:package.json文件解析):
簡單看下項目的依賴(devDependencies)和 scripts,大致瞭解下項目構建,怎麼打包。可以知道構建是通過如下腳本(主要是minify插件對源碼壓縮)執行的:
npm run minify -- --source-map --source-map-url \" \" -o underscore-min.js
查看源碼:
1、首先收攏代碼(不要被代碼量嚇到),可以看到所有的代碼都放到一個閉包裏面,裏面是一個立即執行的函數。
2、展開閉包函數,可以看到首先是全局變量的聲明。
// Baseline setup
// --------------
// Establish the root object, `window` (`self`) in the browser, `global`
// on the server, or `this` in some virtual machines. We use `self`
// instead of `window` for `WebWorker` support.
var root = typeof self == 'object' && self.self === self && self ||
typeof global == 'object' && global.global === global && global ||
this ||
{};// 獲取全部變量
// Save the previous value of the `_` variable.
var previousUnderscore = root._;
// Save bytes in the minified (but not gzipped) version:
var ArrayProto = Array.prototype, ObjProto = Object.prototype; // 保存js引擎的數組和對象的原型
var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
// Create quick reference variables for speed access to core prototypes.
var push = ArrayProto.push,
slice = ArrayProto.slice,
toString = ObjProto.toString,
hasOwnProperty = ObjProto.hasOwnProperty;// 保存js引擎的原型方法
// All **ECMAScript 5** native function implementations that we hope to use
// are declared here.
var nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeCreate = Object.create;
// Naked function reference for surrogate-prototype-swapping.
var Ctor = function(){};
// Create a safe reference to the Underscore object for use below.
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);// 確保全局對象 _ 被安全創建
this._wrapped = obj;
};
// Export the Underscore object for **Node.js**, with
// backwards-compatibility for their old module API. If we're in
// the browser, add `_` as a global object.
// (`nodeType` is checked to ensure that `module`
// and `exports` are not HTML elements.)
if (typeof exports != 'undefined' && !exports.nodeType) {
if (typeof module != 'undefined' && !module.nodeType && module.exports) {
exports = module.exports = _;
}
exports._ = _;
} else {
root._ = _;
}// 暴露全局對象 _ (所有的方法和屬性都在_裏面)
// Current version.
_.VERSION = '1.9.1'; // 版本信息
3、在全局對象上添加方法
可以看到在全局對象_上添加了許多方法map、reduce、……….,這些方法的Api介紹官網都有,這裏就不多說了。
4、函數調試解析,一般方法通過名稱就可以知道它的作用,但是想了解內部實現的話可以通過調試。(TODO)