首先,咱們先去官網把JQ的js相關文件download到本地,看着源碼,仿照寫法,一步步實現而且理解jq的原理。javascript
接着建立一個屬於本身的js文件(取名爲jquerMey-1.0.1js)。html
這裏先說一下解析源碼的幾個步驟:java
學會分析組成及架構 => (JQ經過選擇器(字符串)來檢索全部匹配的DOM,而且進行批量操做,同時可以幫咱們解決瀏覽器的兼容問題。)node
學會看英文註釋(不懂多用騰訊翻譯君[手動滑稽])jquery
先減後刪webpack
閱讀思考做者的語義git
嘗試補全 好的,開搞吧!github
首先創立一個html文件,如圖:web
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jQuery源碼解析</title>
</head>
<body>
<div class="box">這是一個div</div>
<span class="box">這是一個span</span>
<script src="jquery-3.3.1.js"></script>
<!--<script src="sizzle.js"></script>-->
<!--<script src="jquerMey-1.0.1.js"></script>-->
<script type="text/javascript">
var $eles = $('.box');
var $eles = jQuery('.box');
console.log($eles)
$eles.addClass('myFirst')
</script>
</body>
</html>
複製代碼
能夠看到,這邊jQuery.fn.init 輸出的是一個數組,還有一系列方法。咱們一步步來。
這邊先把JQ源碼的全部東西都先刪一下,能夠看到,定義一個匿名函數,建立 閉包。算法
// 定義一個匿名函數,立刻調用它,包起來調用的時候能夠建立閉包
(function(global,factory) {
//內存中動態開闢了一塊空間來執行這個裏面的代碼,對外是封閉的,能夠訪問外面的變量
}(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
/*這裏的三元判斷,除了BOM瀏覽器的運行環境還能運行在什麼環境中? =>node環境 (node運行在V8引擎中,主要用來作中間件)
中間件不少,架構與部署方面的中間件:webpack,grunt,gulp;功能方面的中間件:node.js(頁面靜態化) */
}));
複製代碼
好,接着分析
// 定義一個匿名函數,立刻調用它,包起來調用的時候能夠建立閉包
(function (global, factory) {
//內存中動態開闢了一塊空間來執行這個裏面的代碼,對外是封閉的,能夠訪問外面的變量
/*那麼除了BOM瀏覽器的運行環境還能運行在什麼環境中? =>
node環境 (node運行在V8引擎中,主要用來作中間件) 中間件不少,
架構與部署方面的中間件:webpack,grunt,gulp;功能方面的中間件:node.js(頁面靜態化) */
if (typeof module === "object" && typeof module.exports === "object") {
// For CommonJS and CommonJS-like environments where a proper `window`
module.exports = global.document ?
factory(global, true) :
function (w) {
if (!w.document) {
throw new Error("jQuery requires a window with a document");
}
return factory(w);
};
}
else {
factory(global);
}
}(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
}));
複製代碼
寫到這裏,那麼這裏註釋說的CommonJS是什麼呢?這就涉及到了上面說的node了。
CommonJS是nodejs也就是服務器端普遍使用的模塊化機制。 該規範的主要內容是,模塊必須經過module.exports 導出對外的變量或接口,經過 require() 來導入其餘模塊的輸出到當前模塊做用域中。
能夠看到,這裏並無給factory()傳入第二個參數,默認爲false,則會執行下面if的代碼(即爲BOM環境)。在if語句中,能夠看到jQuery必定是核心代碼,那麼jQuery究竟是什麼呢?繼續看。
這裏的jQuery本質就是一個函數,jQuery有一個fn對象,而且fn有一個init函數。這裏的makeArrray本質是返回一個數組。
往下看,能夠看到這裏jQuery的fn對象其實就是jQuery的原型對象;接着咱們找到init方法。
jQuery.fn = jQuery.prototype = {
init : function (selector, context) {
return jQuery.makeArray( selector, context );
}
};
jQuery.makeArray = function(selector, context){
var $eles = new Sizzle(selector, context);
return $eles;
}
複製代碼
分析完jQuery.fn,咱們看看makeArray。Sizzle.js文件裏面有不少算法方面的代碼,咱們先跳過,繼續分析代碼。此時,咱們用Chrome打開html代碼,能夠看到,輸出如圖:(此時尚未寫addClass函數因此報錯了)
jQuery.fn = jQuery.prototype = {
init : function (selector, context) {
return jQuery.makeArray( selector, context );
},
each: function (func) {
},
addClass : function (className) {
},
removeClass: function (className) {
}
};
jQuery.makeArray = function(selector, context){
var $eles = new Sizzle(selector, context);
$eles.prevObject = arguments.callee;
$eles.__proto__ = jQuery.fn
return $eles;
}
複製代碼
繼續補全,這樣jQuery的 總體架構 就ok了,以後就是往裏面添加東西。
(好比往裏面添加addClass,removeClass,each方法)
jQuery.fn = jQuery.prototype = {
init : function (selector, context) {
return jQuery.makeArray( selector, context );
},
each: function (func) {
for (var i=0;i<this.length;i++) {
func.call(this,i,this[i]);
}
return this;
},
addClass : function (className) {
return this.each(function (index, element) {
element.className += " " + className
})
},
removeClass: function (className) {
return this.each(function (index, element) {
element.className = ""
})
}
};
複製代碼
咱們能夠看到此時控制檯裏面已經有了咱們添加的方法,讓咱們來實驗一下。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jQuery源碼解析</title>
</head>
<style>
.myEleFirst {
display: block;
width: 100px;
height: 100px;
margin: 10px auto;
background: red;
}
button {
display: block;
width: 20px;
height: 20px;
margin: auto;
}
</style>
<body>
<div class="myEle">這是一個div</div>
<span class="myEle">這是一個span</span>
<button onclick="removeClass()"></button>
<!--<script src="jquery-3.3.1.js"></script>-->
<script type="text/javascript" src="sizzle.min.js"></script>
<script type="text/javascript" src="jquerMey-1.0.1.js"></script>
<script type="text/javascript">
var $eles = $(".myEle");
var $eles = jQuery(".myEle");
console.log($eles);
$eles.addClass('myEleFirst');
function removeClass() {
$eles.removeClass("myEleFirst")
}
</script>
</body>
</html>
複製代碼
結果如圖:
附上所有代碼:
/*!
* jqueMey JavaScript Library v1.0.1
*
* Includes Sizzle.js
* https://sizzlejs.com/
*
* Copyright JS Foundation and other contributors
* Released under the MIT license
* Email: huangmiantong@126.com || v_mtonhuang@tencent.com
*
* Date: 2018-12-11T22:04Z
*/
// 定義一個匿名函數,立刻調用它,包起來調用的時候能夠建立閉包
(function (global, factory) {
//在BOM瀏覽器的運行環境
/*那麼除了BOM瀏覽器的運行環境還能運行在什麼環境中? =>
node環境 (node運行在V8引擎中,主要用來作中間件) 中間件不少,
架構與部署方面的中間件:webpack,grunt,gulp;功能方面的中間件:node.js(頁面靜態化) */
//內存中動態開闢了一塊空間來執行這個裏面的代碼
if (typeof module === "object" && typeof module.exports === "object") {
module.exports = global.document ?
factory(global, true) :
function (w) {
if (!w.document) {
throw new Error("jQuery requires a window with a document");
}
return factory(w);
};
} else {
factory(global);
}
}(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
var
version = "1.0.1",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
};
jQuery.fn = jQuery.prototype = {
init : function (selector, context) {
return jQuery.makeArray( selector, context );
},
each: function (func) {
for (var i=0;i<this.length;i++) {
func.call(this,i,this[i]);
}
return this;
},
addClass : function (className) {
return this.each(function (index, element) {
element.className += " " + className
})
},
removeClass: function (className) {
return this.each(function (index, element) {
element.className = ""
})
}
};
jQuery.makeArray = function(selector, context){
var $eles = new Sizzle(selector, context);
$eles.prevObject = arguments.callee;
$eles.__proto__ = jQuery.fn
return $eles;
}
// Expose jQuery and $ identifiers, even in AMD
// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
// and CommonJS for browser emulators (#13566)
if (!noGlobal) {
//BOM必定有window對象
// jQuery必定是核心對象
window.jQuery = window.$ = jQuery;
}
return jQuery;
}));
複製代碼
未完待續...