jquery源碼部分分析

1.總體架構和如何辨別瀏覽器端和node端

自執行函數,判斷在什麼端,若是在瀏覽器端就執行factory函數css

//(function(){a,b})(a,b)
//jq大架構,閉包,自執行函數,傳入函數參數(factory:工廠模式)
(function(global,factory){
  "use strict" //嚴格模式
  if(typeof module ==="object" && typeof module.exports ==="object"){
    //說明支持CommonJS模塊規範的(例如Node)
    //...
  }else{
    //瀏覽器端
    // factory(window) => 就是傳入的函數參數執行 => function( window, noGlobal){
    //    window === window    noGlobal === undefined(由於執行這個函數的時候,沒有傳第二個參數)  
    //}
    factory(global);
  }
})(typeof window !== "undefined" ? window : this ,function( window, noGlobal){

})

/*
參數一:
typeof window !== "undefined" ? window : this
  區分在瀏覽器端運行仍是Node端運行
  typeof xx 若是xx不存在,不會報錯,而是返回undefined(js中的暫時性死區問題)
  typeof window !== "undefined" 這個成立,則他在瀏覽器端或者webView端(瀏覽器端存在window),不存在說明是Node端運行,this代指當前Node模塊
  =>第一個參數就是讓global知道是在什麼端運行的

參數二:factory爲一個函數
function( window, noGlobal){}

*/

2.factory函數

factory爲自執行函數傳入的參數,而且在判斷爲瀏覽器端後執行,而且傳入window對象 factory(global)node

(function(global,factory){
    factory(global);
})
(typeof window !== "undefined" ? window : this ,function( window, noGlobal){
    // $() jQ選擇器
    //由於window.jQuery = window.$ = jQuery,因此咱們$()執行的就是這個函數
    
    var jQuery = function(selector,context){
        return new jQuery.fn.init(selector,context)
    }
    //---------------------------each
    jQuery.fn.each =function (callback){
      //jQuery.each(jQ實例,callback)
       return jQuery.each(this.callback);
    };
    jQuery.each = function(obj,callback){
        //obj能夠是數組(類數組) 或者 對象 =>用來遍歷它們
    }
    //-------------------------extend向jq和jq原型上擴展方法
    //=>向原型擴展方法是給jq實例用的,通常應用於jq插件封裝
    //=>向jq對象中擴展的方法是爲了完善類庫
    //$.fn.extend({})  $.fn.extend(true,{})
    jQuery.extend = jQuery.fn.extend = function(){
        
    }
    
    //--------------------------jQuery是一個類,它的原型上放了好多屬性和方法
    jQuery.fn = jQuery.prototype = {
        //保證原型對象上的構造函數完整性
        constructor : jQuery,
        //...
    };
    //init 也是一個類 
    //new jQuery.fn.init(selector,context) => $()選擇器是建立這個類的一個實例,因此$()就能夠調用init原型上的方法
    //實例本應該指向init.prototype,可是咱們讓init.prototype =jQuery.prototype,因此最終類的init實例的__proto__指向的是jQuery.prototype,也就是相似於建立了一個jQ類的實例 => $()jQ選擇器就是jQ類的一個實例,此實例能夠調取JQ原型上的方法
    var init = jQuery.fn.init=function(selector,context){
        //....
    }
    init.prototype = jQuery.fn = jQuery.prototype;
    
    //衝突處理的( noConflict無衝突) =>$.noConflict()
    //一個項目中引入了多個類庫,其中一個類庫(例如:zepto)用的也是$=>$===Zepto,此時若是也導入了JQ,那麼$到底表明誰就衝突了
    //假設zepto先引入,jq後引入,咱們就把$的使用權給zepto,而後函數中又return了jquery
    //因此,若是有衝突的時候,咱們能夠 let j = $.noConflict(); 之後 j 就代替了$
    var _jQuery = window.jQuery,
        _$ = window.$;
    jQuery.noConflict = function(deep){
        if(window.$ === jQuery){
            window.$ = _$;
        }
        if(deep && window.jQuery ===jQuery){
            window.jQuery = _jQuery
        }
        return jQuery
    }
    
    //這裏爲factory的函數體
    //若是是瀏覽器端運行,條件成立  !undefined
    if(!nonoGlobal){
        //把jQuery或者$暴露到全局對象中(這樣當外部引用了jquery的時候,就能夠直接調用裏面定義的方法)
        window.jQuery = window.$ = jQuery
    }
})

//=>jQ選擇器其實就是把jQuery方法執行
//$() =>function(selector,context){} 讓他執行
//$('.box')獲取當前頁面中樣式類爲box的盒子(範圍/上下文:整個頁面)
//$('.banner .box')獲取.banner的盒子後代爲.box的盒子  =>     等價於$('.box',document.getElementById('banner'))

選擇器

$([selector])
[selector]支持三種類型
    "string" => 基於css選擇器獲取元素 (底層都是使用正則來一點一點匹配的)
    元素節點  => 把DOM元素轉換爲jQ對象 (jQ類的實例)
    函數     =>  $(document).ready(函數) 

1.傳css選擇器爲常見用法
2.傳節點,經常使用於將dom對象轉換爲jq對象,方便調用jq內置方法
    let boxList = document.querySelectorAll('.box')
    let $boxList = $(boxList)  //轉換爲jq對象
    let box1 = $boxList[0] //將jq對象轉換爲原生dom,jq對象
3.傳函數經常使用於開頭,代碼都再傳入的函數中編寫
$(function(){
    //等價於 $(document).ready(函數)  當整個頁面的DOM結構加載完成
})

分析源碼後的一些應用問題

//$('.box')每一次執行都是建立一個JQ的新實例(jQ對象)
// => $('.box') !== $('.box') 兩個不一樣的實例,開闢了兩個堆內存
let $box = $('.box');
$('.box').click(()=>{}) 
$('.box').addClass()
$('.box').fadeIn()
//這樣雖然能實現效果可是,開闢了三個堆內存,消耗性能,因此咱們應該儘可能用一個變量來接收,用這個變量區操做屬性
$box.click(()=>{}) 
$box.addClass()
$box.fadeIn()

//在控制檯輸出jQuery.fn能夠查看原型上的方法,這些方法均可以被實例所調用(此時把jq看做一個類)
//獲取一個實例,再使用dir查看
let $box = $('.box')
console.dir($box)
//但jq也是一個普通對象,再普通對象上也有不少方法,這些方法和實例沒有直接的關係,基於$.xxx()調用,例如:$.Callbacks() 或者 $.ajax() 等 
console.dir(jQuery)
            

---------------------------------------------------------
 //向jquery原型中拓展方法
            $.fn.extend({
                aaa(){  console.log('a') }
            })
------------------------------------------------------------
 //each (當返回值爲false的時候,結束循環,forEach不支持)
 //  =>   $.each($('.box'),function(){})
 // 等價於$('.box').each(function(){})
$.each([10,20,30],function(item,index)=>{})  //不能用箭頭函數,沒有this
$.each({age:10,name:小黃},function(key,value){
    //參數順序和數組的forEach是相反的
    //this => value
})
相關文章
相關標籤/搜索