FE.SRC-逐行分析jQuery2.0.3源碼-完整筆記

概覽

(function (){
   (21  , 94) 定義了一些變量和函數 jQuery=function();  
   (96  , 293) 給jQuery對象添加一些方法和屬性;  
   (285 , 347) extend:jQuery擴展方法;  
   (349 , 817) jQuery.extend : 擴展一些工具方法;  
   (877 , 2856 ) Sizzle : 複雜選擇器的實現;  
   (2880, 3042 ) Callbacks : 回調對象:函數的統一管理  
   (3043, 3183 ) Deferred : 延遲對象:對異步的統一管理  
   (3184, 3295) support : 瀏覽器功能檢測,肯定瀏覽器對某些功能是否支持  
   (3380, 3652) data() : 數據緩存功能  
   (3653, 3797) queue()/dequeue() : 隊列管理  
   (3803, 4299) attr() prop() val() addClass()等方法,對元素屬性的操做  
   (4300, 5138) on() trigger()等方法,事件相關的方法,事件管理  
   (5140,6057) DOM操做:添加 刪除 包裝 獲取 DOM篩選  
   (6058, 6620) css() : 樣式操做  
   (6621, 7854) 提交的數據和Ajax()操做:ajax() load() getJson()  
   (7855, 8584) animite() : 運動的方法  
   (8585, 8792) offset() :位置與尺寸的方法  
   (8804, 8821) JQuery對模塊化的支持  
   (8826) window.jQuery = window.$ = jQuery;//對外提供的接口  
   })();

匿名函數 :14

(function (window,undefined){
})(window)

爲何傳入window

對壓縮和查找都有利javascript

爲何傳入undefined

防止undefined在外部被修改css

嚴格執行 :20

'use strict'
低版本不支持,.net跟蹤不支持。根據項目選型決定是否開啓。html

rootjQuery :23

rootjQuery=jQuery(document);//:866

爲了壓縮,可維護java

core_strundefined :30

core_strundefined=typeof undefined

爲了支持 IE9,從而使用type of xmlNode.method代替xmlNode.method !==undefinednode

變量存儲 :33

location = window.location //:33
document=window.document
docElem=document.documenttElement

core_concat = core_deletedIds.concat, //:52
core_push = core_deletedIds.push,
core_slice = core_deletedIds.slice,
core_indexOf = core_deletedIds.indexOf,
core_toString = class2type.toString,
core_hasOwn = class2type.hasOwnProperty,
core_trim = core_version.trim,

防衝突 :38

_jQuery=window.jQuery
_$=window.$

class2type={} :44

$.tpye() 會用到,clas2type形如 {'[objectt String]'}jquery

core_version="2.0.3" :49

版本號ajax

jQuery聲明

最終$()調用的是這個chrome

//:61
jQuery = function( selector, context ) {
    return new jQuery.fn.init( selector, context, rootjQuery );
},

jQuery 原型

//:96
jQuery.fn = jQuery.prototype = {
    jquery: core_version,
    constructor: jQuery,
    init: function( selector, context, rootjQuery ) {...}
}
//:283
jQuery.fn.init.prototype = jQuery.fn;

實際上jQuery.prototype.init.prototype = jQuery.prototype。以後的的代碼就能夠寫成顆粒化的調用操做,形如jQuery().css()json

通用正則

數字

//:67
core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,

非空字符,好比單詞

core_rnotwhite = /\S+/g,

html標籤

防止經過location.hash的XSS注入(#9521)數組

rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,

獨立空標籤

好比 <p></p>

rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,

IE駝峯轉換

-ms-aaa-bbb轉換成MsAaaBbb

rmsPrefix = /^-ms-/,

普通駝峯轉換

rdashAlpha = /-([\da-z])/gi,

jQuery.prototype :98

jquery:版本 :100

jquery: core_version,

constructor:修正指向問題

constructor: jQuery,
不寫容易被修改,例如

//Aaa
Aaa.prototype.name='hello'
Aaa.prototype.age=30

//Object
AAA.prototype={
    name:'hello',
    age:30
}

init:初始化和參數管理 :101

對傳入的參數分別處理

忽略的

$(""), $(null), $(undefined), $(false)

字符的

if 字符左側是`<`且右側是`>`且長度 大於3
    //$('<li>') $('<li>1</li><li>2</li>')
    match=[null,'<li>',null]
else
    match=null //$('.box') $('div') $('#div1 div.box')
    match=['$#div1',null,'div1']//$('#div1')
    match=['<li>hello','<li>',null] $('<li>hello')
if ( match && (match[1] || !context) ) {// :120
    //$('<li>') $('#div1')
    if(match[1]){
        //HANDLE: $(html) -> $(array)
        使用jQuery.parseHTML將html代碼轉數組
        使用jQuery.merge將json轉數組
        
        // HANDLE: $(html, props)
        if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) 
        
        
    }else{
        //HANDLE: $(#id) :151
        elem = document.getElementById( match[2] );
        //黑莓4.6兼容代碼 :155
    }
// HANDLE: $(expr, $(...))
}else if ( !context || context.jquery ) {

// HANDLE: $(expr, context) 例如 $(context).find(expr)
} else {

}
// HANDLE: $(DOMElement)
else if ( selector.nodeType ) {

// HANDLE: $(function)
else if ( jQuery.isFunction( selector ) ) {

jQuery.makeArray 將dom集合轉數組或對象

selector:存儲選擇字符串

length:this對象的長度

toArray():轉數組 :202

return core_slice.call( this );
$('div'):{0:div,1:div,length:2} =>[div,div]
實際是調用slice

get():轉原生集合 :208

根據num返回所有或其中某個元素

get: function( num ) {
    return num == null ?
        this.toArray() :
        ( num < 0 ? this[ this.length + num ] : this[ num ] );
},

pushStack():jQ對象入棧 :220

一個棧裏放1個jQ對象,1個jQ對象包含1個或多個dom

each():遍歷集合 :236

工具方法jQuery.each

ready():DOM加載的接口 :240

工具方法jQuery.reday.promise.done(fn)

slice():集合的截取 :247

棧操做 this.pushStack( core_slice.apply( this, arguments ) );

first():集合的第一項

this.eq( 0 )

last():集合的最後一項

this.eq( -1 )

eq():集合的指定項

map():返回新集合

return this.pushStack( jQuery.map(this, function( elem, i ) {
    return callback.call( elem, i, elem );
}));

end():返回集合前一個狀態

return this.prevObject || this.constructor(null);

push(): 內部使用

core_push

sort(): 內部使用

[].sort,

splice(): 內部使用

splice: [].splice

jQuery.extend

拷貝方法 :285

定義一些變量
if(){}    看是否是深拷貝狀況
if(){}    看參數正確不
if(){}    看是否是插件狀況
for(){    可能有多個對象狀況
    if(){}        防止循環引用
    if(){}        深拷貝
    else if(){}     淺拷貝
}

防止循環引用

if ( target === copy ) {
    continue;
}

深拷貝

if ( copyIsArray ) {
    copyIsArray = false;
    clone = src && jQuery.isArray(src) ? src : [];

} else {
    clone = src && jQuery.isPlainObject(src) ? src : {};
}

// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );

淺拷貝

target[ name ] = copy;

工具方法

jQuery.extend({
    expando:生成惟一jQ字符串(內部)
    noConflict():防止衝突
    isReady: dom是否加載完(內部)
    readyWait:等待多少文件的計數器(內部)
    holdReady(): 推遲dom觸發
    ready():準備dom觸發
    isFunction():是否爲函數
    isArray():是否爲數組
    isWindow():是否爲window
    isNumberic():是否爲數字
    type():判斷數據類型
    isPlainObjeect():是否爲對象自變量
    isEmptyObject():是否爲空的對象
    error():拋出異常
    parseHTML():解析節點
    parseJSON():解析JSON
    parseXML():解析XML
    noop():空函數
    globalEval():全局解析js
})

expando 惟一映射 :351

生成惟一jQuery字符串,作映射關係用

expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),

noConflict 防止衝突 :353

if ( window.$ === jQuery ) {
    window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
    window.jQuery = _jQuery;
}
return jQuery;

dom加載相關

jQuery.ready.promise

if ( document.readyState === "complete" ) {
    // 防止Ie的提早執行
    setTimeout( jQuery.ready );
} else {
    // 若dom加載了則執行,不然監聽完成後執行
    document.addEventListener( "DOMContentLoaded", completed, false );
    window.addEventListener( "load", completed, false );
}

readyList

holdReady(hold) :373

爲true時執行ready,不然readyWait計數

if ( hold ) {
    jQuery.readyWait++;
} else {
    jQuery.ready( true );
}

ready(wait) :382

//若是有wait,或者ready,停止
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
    return;
}
jQuery.isReady = true;
// 若是被觸發,那麼遞減,若是須要則等待
if ( wait !== true && --jQuery.readyWait > 0 ) {
    return;
}
//若是有函數綁定,則執行。
readyList.resolveWith( document, [ jQuery ] );
// 觸發任何綁定事件
if ( jQuery.fn.trigger ) {
    jQuery( document ).trigger("ready").off("ready");
}

type(obj) :423

if ( obj == null ) {
    return String( obj );
}
// 兼容: Safari <= 5.1 
return typeof obj === "object" || typeof obj === "function" ?
    class2type[ core_toString.call(obj) ] || "object" :
    typeof obj;

isWindow(obj) :415

不爲空且window屬性相同(undefined 沒有屬性)

return obj != null && obj === obj.window;

isNumeric(obj) :417

typeof NaN 或 finite ==='number'

return !isNaN( parseFloat(obj) ) && isFinite( obj );

parseHTML(data, context, keepScripts) :475

//校驗輸入
parsed=正則匹配data
//單標籤
return context.createElement( parsed[1] )
//多標籤
//判斷是否保留script
parsed = jQuery.buildFragment( [ data ], context, scripts )
return jQuery.merge( [], parsed.childNodes );

globalEval(code) :528

直接調用eval沒法全局訪問,必須先賦值

var indirect = eval;
if 'use strict'
    createElement
    document.head.appendChild( script ).parentNode.removeChild( script )
else
    indirect(code)

camelCase :552

修正IE,駝峯轉換

return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase )

nodeName( elem, name ) :556

全轉小寫判斷是否相同

return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();

each( obj, callback, args ) :561

i=0
length=obj.length //若json則不存在
isArray=isArraylike(obj)

if isArray
    for(;;)
        callback.call
else 
    for in
        callback.call

makeArray :615

類數組轉數組

if isArraylike( Object(arr) 
    jQuery.merge
else
    core_push

inArray( elem, arr, i ) :632

indexOf

return arr == null ? -1 : core_indexOf.call( arr, elem, i );

merge( first, second ) :636

獲取2個變量的length

if 非json

for
    first[ i++ ] = second[ j ]

else

while
    first[ i++ ] = second[ j++ ]

grep( elems, callback, inv ) :656

過濾新數組

for
    retVal = !!callback( elems[ i ], i )
    if inv !== retVal
        ret.push( elems[ i ] )

map( elems, callback, arg ) :676

//分別處理arr 和json
for
    value = callback( elems[ i ], i, arg );
    if ( value != null ) {
        ret[ ret.length ] = value;
    }
return core_concat.apply( [], ret );

proxy( fn, context ) :713

context 如果string 
    content=fn(content)
return function(){
    return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) )
}
proxy.guid = fn.guid = fn.guid || jQuery.guid++

access( elems, fn, key, value, chainable, emptyGet, raw ) :742

elems $('#div1')
fn 回調函數
key,value {background:'red'}

if  type(key) ==='object'
    for
        access
else if value !== undefined
    //空
    //非函數
    //函數

swap( elem, options, callback, args ) :798

設置display可見
設置visibility:hidden
獲取樣式
屬性再轉回去

isArraylike(obj) :848

判斷不是window

nodeType==1&&length #是節點 返回true
return type === "array" 
        ||type !== "function" 
            &&( length === 0 
                ||typeof length === "number"
                && length > 0 
                && ( length - 1 ) in obj )

createOptions(options)

將'once memory'=>{once:true,memory:true}
each

obj[flag]=true

jQuery.Callbacks(options) :2880

once// fire for list
memory//add()時直接執行
unique//重複函數,add()時判斷去重
stopOnFalse//fire for list

add(arg)

分別判斷arg=aaa
            arg=aaa,bbb
            arg=[aaa,bbb]
    if menory==true
        fire

remove(arg) :2965

分隔數組

has(fn) :2987

jQuery.InArray

fireWith(context,args) :3018

if list && ( !fired || stack )
        if firing
            stack.push(args)
        else
            fire(args)

Deferred(func) :3045

異步操做,延遲對象,基於$.Callbacks()
$.ajax(url).done(=>resolve).fail(=>reject)

"resolve", "done", jQuery.Callbacks("once memory"), "resolved"

成功
resolve=>fire
done=>add

"reject", "fail", jQuery.Callbacks("once memory"), "rejected"

失敗
reject=>fire
fail=>add

"notify", "progress", jQuery.Callbacks("memory")

notify=>fire
progress =>add

when() 批量延遲:3133

內部有個計數器,當$.when(a(),b(),c()) 中的arguments.length隨着done()後減小到0,實際執行$.Deferred->resolve()
參數必須返回deferred延遲對象,否則則跳過該項。

support 功能檢測:3184

統一兼容性問題。

checkOn複選框value值

老版本chrome是‘’,新的是‘on’

optSelected下拉菜單子項第一項選中

ie不會選中

noCloneChecked 克隆複選框的選中狀態

ie9,10沒有選中

focusinBubbles 選中的冒泡機制

data 數據緩存 :3308

key 自定義屬性,<div JQueryxxxx="x">
set,get,access,remove,hasData,discard
相關文章
相關標籤/搜索