jQuery2.x源碼解析(構建篇) html
jQuery2.x源碼解析(設計篇) node
jQuery2.x源碼解析(回調篇) jquery
jQuery2.x源碼解析(緩存篇) webpack
筆者閱讀了園友艾倫 Aaron的系列博客《jQuery源碼分析系列》,跑艾倫的部分代碼後,感受仍然不夠解渴,對jQuery依舊只知其一;不知其二,產生了不少問題。閱讀源碼博客已經沒法解決這些問題,因此筆者決定親自查看jQuery源碼,解除心中的疑問。閱讀的形式屬於自問自答,筆者會提出疑問,而後親自解答(吐槽:感受有點像一休哥和將軍大人>_<)。git
問題的來源主要有3種:es6
1.在閱讀園友艾倫博客後產生的疑問github
2.之前就有疑問,艾倫博客卻沒有解答或者解釋不夠明白web
3.閱讀源碼的過程當中產生的疑問npm
因此這個jQuery源碼解析系列並不是教程,而是筆者的學習jQuery源碼的筆記,所以纔會採起問答這種不繫統的形式。若是你們想系統學習jQuery源碼,還請仔細閱讀艾倫 Aaron的博客;或是直接閱讀jQuery在gitbub上的源碼(目前的master版本是2.2-stable,筆者閱讀的也是這個版本的代碼)。若是在閱讀後也和筆者同樣,對一些內容存在疑問,能夠看看筆者的系列博客,看看你有沒有你疑惑的問題;若是沒有就發問給我,咱們一塊兒思考答案。json
在我開始閱讀jQuery的源碼時,發現源代碼自己是有模塊化的,而艾倫 Aaron閱讀的版本沒有,他是直接閱讀的dist後的代碼。那麼jQuery是如何構建源代碼的呢?
答:閱讀jQuery在github上的README.md文件,裏面已經說得很是清楚了。先安裝git客戶端和nodejs及npm。而後將github上的資源克隆到本地,找一個目錄,而後打開命令行,輸入git的clone命令:
git clone git://github.com/jquery/jquery.git
本地就會克隆出jQuery的源代碼:
而後進入該目錄下,在命令行上運行以下命令,jQuery就會自動安裝npm模塊,並構建jQuery了。
npm run build
最後在dist目錄中,會構建出咱們想要的jQuery文件了。
答:具體目錄結構能夠看上圖,這裏逐個介紹一下各個目錄和文件的做用:
.github | git相關目錄 |
build | 構建相關的腳本文件,筆者大概閱讀了一下,主要是建立兩個Grunt任務,負責構建(bulid)和輸出(dist) |
dist | 輸出構建後的文件,主要是jquery.js和jquery.min.js,以及jquery.min.map。這些就是咱們最終使用的js文件了 |
external | 放依賴的第三方代碼,jQuery中最重的第三方庫sizzle就在這裏 |
node_modules | nodejs的模塊文件,構建時候安裝的node非全局模塊都放在這裏,屬性nodejs的小夥伴應該很清楚了 |
src | jQuery自身的源代碼的目錄,這就是咱們主要閱讀的部分 |
test | 單元測試用例 |
.babelrc | Babel的配置文件 |
.editorconfig | editorconfig的配置文件,editorconfig是幫助開發者在不一樣的編輯器和IDE之間定義和維護一致的代碼風格的配置,不少ide都支持editorconfig的插件,使用這個就可使各類ide下都能自動將代碼顯示成editorconfig約定的格式 |
.eslintignore | eslint相關文件,配置不用於eslint語法檢測的文件目錄 |
.eslintrc.json | eslint的配置文件。eslint和jshint比較像,能夠認爲是jshint的升級版,都是用來作語法檢測的。 |
.gitattributes | git相關文件,用於設置文件的對比方式 |
.gitignore | git的配置文件,配置用於配置不須要加入版本管理的文件 |
.mailmap | 貌似是一個郵件地址列表 |
.npmignore | npm相關文件,配置哪些文件不須要被髮布到npmjs.org |
.npmrc | npm的配置文件 |
.travis.yml | Tarvis-CI的配置文件,持續集成用的,github整合了持續集成服務travis,每一次push以後,travis就會定時執行「npm test」 來測試項目 |
AUTHORS.txt | 貢獻者名錄 |
CONTRIBUTING.md | 貢獻代碼指引 |
Gruntfile.js | Grunt的配置文件 |
LICENSE.txt | 受權協議 |
README.md | github項目的說明文檔 |
package.json | npm的包文件 |
幾個地方值得注意一下:
1.jQuery是用RequireJs作模塊化工具的,因此jQuery的源代碼是用AMD規範。AMD這個模塊化規範主要活躍於基於瀏覽器的js模塊管理,他有着異步加載、依賴前置等很是好的特性,固然用來作後端的代碼模塊管理也能夠,可是筆者終究認爲這裏用AMD有點「大材小用」了。jQuery用AMD規範作模塊化管理,多是歷史緣由的影響,早些年模塊化工具不像現在這麼成熟。
2.jQuery是用Grunt構建的,jQuery本身作了構建的Grunt任務,具體代碼能夠參考build目錄下的Grunt任務和Grunt的配置文件Gruntfile.js。基於Grunt,jQuery完成測試、構建、合併代碼、壓縮等工做,最終把構建好的文件拷貝到dist目錄裏面。
3.jQuery配置了npm包相關的配置,說明jQuery自己也被髮布到了npmjs.org上,咱們能夠直接用npm安裝jQuery。
4.jQuery有Babel的配置文件,那源代碼是否是用ES6的語法呢?
答:答案是沒有的,咱們先不看Babel在Grunt裏面的配置,直接試一下能不能在源代碼中使用ES6。
先將源代碼裏面添加一條ES6的語法,而後執行構建。這時咱們會發現構建的時候會報錯,並且構建好的jQuery.js文件中ES6的語法也沒有被轉換爲ES5的語法。這說明構建源代碼的時候並無啓用Babel。
咱們在來看Babel在Grunt裏面的配置
babel: { options: { sourceMap: "inline", retainLines: true }, nodeSmokeTests: { files: { "test/node_smoke_tests/lib/ensure_iterability.js": "test/node_smoke_tests/lib/ensure_iterability_es6.js" } } },
能夠看出,Babel僅是將測試用例中的冒煙測試用例作了轉換,而源代碼則不在被轉換列表中。
閱讀jQuery的源代碼,咱們能夠很清楚的看到AMD規範的語句。
而後在dist裏面的構建好的文件中,咱們卻找不到AMD規範語句的影子,jQuery是如何去掉了這些AMD語句呢?
答:起初筆者認爲是用了一些Grunt上的插件,後來閱讀了build裏面的代碼才發現,是在build裏面使用正則將AMD語句去除。jQuery雖然是用的AMD作模塊化,可是具體的代碼結構仍是有本身的一套策略,這個應該就是爲了最後構建代碼而考慮的。
src的根目錄下,共有20多個js文件,不少js文件都有同名的目錄與之對應。目錄之中最特別的目錄就是var目錄,由於var目錄並不存在與之對應的名爲var.js的文件。
var這個名字和js的關鍵字var相同,這和這個目錄這樣命名確定是有關係的。沒錯,jQuery在去除AMD語句的時候,發現若是是var目錄裏的文件的話,就會將其轉換爲「var 文件名 = AMD輸出的對象」的形式。以下圖:
define( 'var/arr',[],function() { "use strict"; return []; } ); define( 'var/document',[],function() { "use strict"; return window.document; } ); define( 'var/getProto',[],function() { "use strict"; return Object.getPrototypeOf; } ); ......
源代碼的這幾個模塊最終會把構建爲:
var arr = []; var document = window.document; var getProto = Object.getPrototypeOf;
......
而對於非「var」目錄下的模塊,jQuery會將define關鍵字等AMD相關的語句直接移除。其中sizzle模塊更爲特殊,jQuery在構建的時候還作了更多的操做,這裏就再也不細究了。
分析到這你們也能看出,jQuery這樣構建是會破壞AMD各個模塊的做用域的。咱們之因此須要模塊化咱們的代碼,一點是不但願咱們把咱們的內部(私有)變量聲明到全局做用域中,而JavaScript是一種函數級做用域的語言,jQuery在構建的時候去掉了AMD的函數形式,這樣全部模塊的代碼構建後的都會在同一個做用域裏,因此在修改jQuery源代碼的時候必定要當心,不要在做用域裏面隨意建立相同名稱的變量,防止形成模塊間的衝突。
以上就是jQuery去除AMD的過程。
不少地方的註釋,都有(#xxxx)的字樣,以下:
// Use the original fragment for the last item // instead of the first because it can end up // being emptied incorrectly in certain situations (#8070).
答:這些是使用者提出的bug,jQuery的做者們根據bug修復的補丁。jQuery的源碼在github上,bug大多都被提到了github上的issues裏面,裏面的每一個bug都有個編號,就是#後面的幾個數字,地址「https://github.com/jquery/jquery/issues/」加上這個編號就是bug所在的url了。進入這個url能夠查看具體的bug說明和jQuery的做者們對於這個bug的修復狀況。除了github的issues,jQuery在其官網也有一個buglist(「https://bugs.jquery.com/ticket/」),不過如今好像訪問不了了,這個網站的後面一樣有一串數字,#xxxx也有可能指的是這個網址裏面bug的id。
瞭解了jQuery的構建過程後,咱們就能夠輕鬆愉快地瀏覽jQuery的源代碼了。事實上若是jQuery構建的時候採用webpack這樣的工具就簡單多了。jQuery沒有采用這樣的工具可能也是歷史緣由,或者是出於進一步優化代碼的目的。