繼續咱們的jQuery源碼解析。
(function(){
? ? ? ?
原文中此處為鏈接,暫不支持采集
? ? ? ? (96?,?283)?給JQ對象,添加一些方法和屬性
? ? ? ? (285?,?347)?extend?:?JQ的繼承方法
? ? ? ? (349?,?817)?jQuery.extend() :?擴展一些工具方法
????????(877?,?2856) ?Sizzle?:?復雜選擇器的實現
? ? ? ? (2880?,?3042)?Callbacks?:?回調對象?:?對函數的統一管理
? ? ? ? (3043?,?3183)?Deferred?:?延遲對象?:?對異步的統一管理
? ? ? ? (3184?,?3295)?support?:?功能檢測
? ? ? ? (3308?,?3652)?data() :?數據緩存
? ? ? ? (3653?,?3797)?queue() :?隊列方法?:?執行順序的管理
? ? ? ? (3803?,?4299)?attr()?prop()?val()?addClass()等?:?對元素屬性的操作
? ? ? ? (4300?,?5128)?on()?trigger() :?事件操作的相關方法
? ? ? ? (5140?,?6057)?DOM操作?:?添加?刪除?獲取?包裝?DOM篩選
? ? ? ? (6058?,?6620)?css() :?樣式的操作
? ? ? ? (6621?,?7854)?提交的數據和ajax() :?ajax()?load()?getJSON()
? ? ? ? (7855?,?8584)?animate() :?運動的方法
? ? ? ??(8585?,?8792)?offset() :?位置和尺寸的方法
? ? ? ??(8804?,?8821)?JQ支持模塊化的模式
? ? ? ? (8826) ?window.jQuery?=?window.$?=?jQuery;
? ? })();
第一部分,已經簡單地分析完畢了,
當我分析完的代碼,我都會在前面打'
原文中此處為鏈接,暫不支持采集
',說明咱們這一塊已經讀完,
大家也可以直接點擊跳轉相應的內容,
接下來,咱們來看第二塊,
第二部分,差不多200行代碼,
這一塊兒是干嘛的呢?
這一塊就是給jQuery添加一些常用的屬性和方法,
其實我們知道jQuery就是基于面向對象的程序,
所以說面向對象就離不開來屬性和方法,
這一塊,我也給它進行了簡化處理,
我們先來看一下這個簡化的代碼。
<script>
? ? jQuery.fn = jQuery.prototype{ // ?添加實例屬性和方法
????????jQuery:版本
????????constructor:修正指向問題
????????init():初始化和參數管理
????????selector:存儲選擇字符串
????????length:this對象的長度
????????toArray():this對象的長度
????????get():轉原生集合
????????pushStack():JQ對象的入棧
????????each():遍歷集合
????????ready():DOM加載的接口
????????slice():集合的截取
????????first():集合的第一項
????????last():集合的最后一項
????????eq():集合的指定項
????????map():返回集合前一個狀態
????????push():(內部使用)
????????sort():(內部使用)
????????splice():(內部使用)
}
</script>
這里面的方法都在后面加上了括號,
屬性是不加括號的,
這些方法和屬性大家看著有點比較眼熟吧,
那咱們也一個一個分析,從第一個看起,
先看一下這個版本,版本這個屬性是什么?
????jquery: core_version,
其實版本就是指向這個變量,
這個變量咱們前面看見過,
core_version= "2.0.3",
就是這個字符串,
所以咱們可以找到這個版本這個屬性,
版本這個屬性可能會在后面的代碼上用到,
所以咱們先了解了解這個,
咱們來找一下這一個屬性,
<!-- 咱們先引入jQuery庫 -->
<script src="./jquery-2.0.3.js"></script>
<script>
????// 很簡單,我們想創建一個jQuery對象
????// 然后再來找一下這一個屬性,看一下現在的版本是多少
????????alert($().jquery);
</script>
彈出的結果如下:
這時的版本就是這個2.0.3這個版本。
OK,咱們在往下,看下面的這塊,
constructor:修正指向問題
咱們來看下源碼,就是這句話,
constructor: jQuery,
如果了解面向對象的小伙伴,
應該知道constructor是什么,
constructor在面向對象當中,
創建出來的對象所擁有的一個屬性,
這個屬性就指向這個對象所屬的構造函數,
比如我們來簡單的來寫一寫,
// 假如我在這里寫一個構造函數
????function Aaa(){
}
// 然后我們來創建一個對象
????var a1 = new Aaa();
// a1下邊就會自動生成constructor這個屬性
????alert(a1.constructor);
彈出來的結果如下:
可以發現這個屬性彈出來的就是這個對象對應的構造函數,
所以說當寫完這個函數之后,這個屬性就已經生成了,
在JS源碼當中,不是jQuery源碼哈,
// 當一個函數創建完成后,就會在原型下添加constructor屬性
// 指向的就是這個構造函數
Aaa.prototype.constructor = Aaa;
這句話是JS源碼當中自動生成的,
所以當我們調用的時候是可以找到它的,
既然是自動生成的,
為什么jQuery還要手動地去指向一下呢?
原因是因為它這種寫法是把指向改了,
咱們來看一下啊,
function Aaa(){
}
// 比如說我們現在不指向Aaa,指向數組
????Aaa.prototype.constructor = Array;
????var a1 = new Aaa();
????alert(a1.constructor);
這樣的話一彈出結果,
發沒發現就跑到這個數組上面去了,
所以constructor這個屬性非常容易會
被我們不經意之間就修改掉了,
所以說有些特殊情況需要修復一下,
比如,什么樣的特殊情況,我們來看下,
????function Aaa(){
}
// 比如我們給原型下添加兩個屬性
????Aaa.prototype.name = 'Hello';
????Aaa.prototype.age = 20;
????var a1 = new Aaa();
????alert(a1.constructor);
現在這樣寫完之后這是沒有任何問題的,
而且我們知道原型本身就是對象,
既然它是對象,我們也可以改成簡寫方式,
Aaa.prototype = {
????????name:'Hello',
????????age:20
}
這兩種寫法其實是一樣的,
在大部分的情況下都是沒有區別的,
但是在面向對象當中呢,
這兩種寫法是有區別的,
我們先來看一下上邊的寫法,
彈出來的結果如下,沒有任何問題,
接下來,我們看下面這種寫法,
彈出的結果如下:
發沒發現這個并不是Aaa了,
而是object這個對象構造函數,
這個是怎么回事呢?
上面這種寫法這個name和age,
都是往原型上添加處理,
所以說默認添加,
這句話是不會受到任何影響的,
但是,下面這一種就不一樣了,
這種寫法不是添加,
而是對這個原型進行覆蓋,
所以這時的constructor,
肯定是指向覆蓋它的這個對象所對應的構造函數,
所以說指向就出現問題了,
既然指向出了問題了,我們平時用的時候,
還需要將它的這個指向修正過來,
要不然后期用的時候,
肯定是會找不到或出問題的,
所以說經常我們會去修正它,
就是讓它指向正確給它修正一下,
Aaa.prototype = {
????????constructor:Aaa,
????????name:'Hello',
????????age:20
}
修正完了,再來看一下結果,
修正完了后是不是就正確了,
這時大家就知道了jQuery源碼
為什么會寫這一句話,
這就是解決這句話的一個原因,
下邊我們來看一下init這個方法,
init():初始化和參數管理
前面我們都知道在對外提供接口的時候,
是不是只有 $ 和 jQuery 這兩個,
$();
jQuery();
?$ 就是jQuery的簡寫方式,
其實它們倆就是同一個函數,
最終都調到哪個函數?
前面我們也說過就是下面這個,
// 第60行開始
// Define a local copy of jQuery
????jQuery = function( selector, context ) {
????????// The jQuery object is actually just the init constructor 'enhanced'
????????return new jQuery.fn.init( selector, context, rootjQuery );
????},
調到這個接口之后,
里面真正的構造函數,
其實是這個init,
所以說對外接口兩個參數傳過來的時候,
一個是元素,另一個是作用域,
這兩個傳過來之后,
它們都傳到了init當中了,
還是在init當中進行處理的,
而第三個參數是沒有提供給我們的,
只是它內部寫的一個根節點,
其實在jQuery當中可以接收的類型非常之多,
這個init會對這些類型簡單的分配,
然后再分別的進行處理,
// 107行
// HANDLE: $(""), $(null), $(undefined), $(false)
????????if ( !selector ) {
????????????return this;
????????}
這一塊就是對注釋的進行處理,
其實當我們有的時候寫一些不正確的選擇元素的時候,
然后它去判斷了字符串,
// 109行
// Handle HTML strings
????????if ( typeof selector === "string" ) {
????????????if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
????????????????match = [ null, selector, null ];
????????????} else {
????????????????match = rquickExpr.exec( selector );
????????????}
既然是判斷字符串的話,
那么說明,$選擇的有id、class、標簽,
或者一些更復雜的,
是不是這些都是字符串啊,
????$('#box1');
????$('.box2');
????$('div');
????$('#div div.box');
除了這種選擇字符串的方法,
還有類似于如下的,
????$('<li>');
咱們都知道這樣寫是創建一個li標簽,
所以字符串不僅可以選擇,還可以創建,
所以說這個字符串的類型也比較多,
比如還有一些稍微復雜一點的創建,
$('<li>1</li><li>2</li>');
其實都是走的這個字符串判斷,
接下來它是對哪里進行處理的呢?
// 176行 ??
// HANDLE: $(DOMElement)
????????} else if ( selector.nodeType ) {
????????????this.context = this[0] = selector;
????????????this.length = 1;
????????????return this;
這一塊的對DOM元素進行處理的,
// 比如選擇的this
????$(this);
// 或者document
????$(document);
就會走這里。
接著往后,比如說下面這一塊,
// HANDLE: $(function)
????????// Shortcut for document ready
????????} else if ( jQuery.isFunction( selector ) ) {
????????????return rootjQuery.ready( selector );
????????}
這一塊處理的是 $ 傳函數的形式,
// 比如說加個函數 ?
// 咱們平時用它做文檔加載
// 所以傳函數的形式該怎么處理
????$(function(){
})
好,就是這樣一個順序,
下邊就是下面這一塊了,
return jQuery.makeArray( selector, this );
這一塊就比較簡單,
它處理的是數組和對象的形式。
所以我們簡單把init框架寫一下,
$(' '),$(null),$(undefined),$(false)
$('#div1'),$('.box'),$('div'),$('#div div.box')
$('<li>'),$('<li>1</li><li>2</li>')
第一塊其實很簡單,
就是當你寫錯的時候,
無非就是走if了,
讓它直接返回,
就不讓它繼續往下執行了,
這個其實很簡單,
程序也不會說有問題會報錯啊,
或者是影響到下邊的運行啊,
return 對象是很正常的,
這個對象就會在外面生成的。
OK,這一節咱先講到這里
回看上一集:
原文中此處為鏈接,暫不支持采集
別走開,下集更精彩。
喜歡文章的小伙伴,
希望大家多多轉發分享,
你的分享就是我的動力!
or