jQuery源碼初探(1)


前言

本人也是剛入坑的一枚小白,到現在差不多快一年了啊…
對於前端的同志來說,jQuery應該是再熟悉不過了吧,因為就目前來看,80%左右的網站或多或少的都直接或間接引用jQuery,可以毫不客氣地說它目前來說最流行的,面向對象的JavaScript框架,因為平時使用頻率很高,所以也就萌生了閱讀源碼的想法,並結合自己的目前知識,照着源碼一點點的分析吧…
(ps:本人前端小白,也是最近才開始閱讀源碼,邊讀邊寫,所以如果有分析不對或者分析不當的地方,還請諒解,也會很樂意接收大家的批評和指正..)

下面進入正題吧

1. 本文分析jQuery版本為3.0.0版本,在官網上下載對應未壓縮版即可jQuery官網
2. 轉載請注明出處

ok;打開jQuery-3.0.0的源碼我們發現,一開始就是這么一段代碼

( function( global, factory ) {

"use strict"
;

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 ) {
/******此處省略若干行*******/
}));

一開始看的時候,可能會找不到 function( window , noGlobal){} 這個函數的結束部分,其實,這個函數是jQuery的主體,貫穿整個jQuery的框架,我們所使用的所有的jQuery方法都是寫在這個部分。

我們先拋開里面的代碼不看,只看外部的框架,我們可以將其簡化為

( function( global, factory ) {
/******此處省略若干行*******/
}( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
/******此處省略若干行*******/
}));

這種寫法叫做IIFE (immediately-invoked function expression),也叫‘’立即執行函數‘’‘’即時執行方法‘’等,意思就是函數會在創建完成的時候自動執行一次,一般來說寫法有主要有兩種寫法:

  1. 第一種:就如同jQuery寫法一樣
    ( function( a , b , c ){
/***執行的代碼***/
}( 參數1 , 參數2 , 參數3 ) );
  1. 第二種
    ( function( a , b , c ){
/***執行的代碼***/
})( 參數1 , 參數2 , 參數3 );

這兩種寫法 參數1,參數2,參數3分別對應的匿名函數的 a , b , c;

ok,問題來了,為什么jQuery要采用IIFE?那么使用IIFE有什么好處?

因為在ES6以前,JS是沒有塊級作用域的概念,只有函數作用域,作為一種對塊級作用域的模擬就只能用function模擬,就是為了使模塊相互獨立,降低模塊間的耦合性,避免全局作用域的污染和全局變量的沖突。

舉個例子

    /**用IIFE創建一個閉包**/
var foo = (function(){
var txt = "hello";
return {
get: function(){
return txt
},
set: function( val ){
txt = val
}
}
})();

console.log( foo.get() ); // 'hello'
foo.set( 'world' );
console.log( foo.get() ); // 'world'

foo.txt; //'undefinded'
console.log( txt ) // 'ReferenceError : txt is not defined'

可以看出,我們就是可以通過 導出方法 從函數外部的外部去更改 改變函數內部變量的值,所以就可以利用這個特點來隔離作用域,模擬一種“私有”的效果,jQuery正是利用這一點,在我們調用jQuery代碼時,保護jQuery內部變量。(ps:如果有不熟悉的同學,可以去看看作用域鏈和閉包的相關知識哈~)

好的,我們回到上面jQuery的部分,

( function( global, factory ) {
/******此處省略若干行*******/
}( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
/******此處省略若干行*******/
}));

在函數 參數 global 中 , jQuery采用了 一個三元運算符去賦值

typeof window !== "undefined" ? window : this

首先用 typeof 來判斷 當前的 window 存不存在 , 如果存在 , 就將 window對象傳入 , 否在就傳入this對象。jQuery之所以這么寫,是因為 global 如果是在瀏覽器環境就是 window , 如果不是在瀏覽器環境則是其他的全局對象,這樣 傳遞this可以保存當前的上下文環境;

接下來理一理這一部分代碼。

這里寫圖片描述

我直接截取了源碼的一段

首先我們 看這個判斷 :

 if ( typeof module === "object" && typeof module.exports === "object" ) 

結合注釋,我們 能大概看懂, 這一段判斷是 為了 兼容 commonjs 或者 類似 commonjs 規范的一些框架;
了解過node.js的同學應該能看出來 module.exports 是 node.js 中用來創建模塊的方法,那么可以理解為如果這個條件成立,那么 首先判斷當前的環境是否支持 global.document 屬性 , 也就是window.document 屬性 , 如果支持 , 我們調用

 `factory( global, true ) { /* jQuery code * / }`

將 jQuery 的方法綁定到當前模塊上,

如果 window.document 不存在呢? 直接調下面的方法

    function( w ) {
if ( !w.document ) {
throw new Error( "jQuery requires a window with a document" );
}
return factory( w );
};

該方法拋出一個異常 , 告訴用戶 jQuery 需要 window.document 環境 , 並依舊返回 factory( w ) 方法(ps:其實 我也不知道 為什么 不支持 ,還要返回 factory( w ) 方法 , 0.0 );

如果

 if ( typeof module === "object" && typeof module.exports === "object" ) 

這個條件不成立,也就是我們 一般 遇到的情況,(一般情況下,typeof module 都是 ‘undefined’),
這樣就好辦了,直接調用 factory( global ) 將 jQuery 方法引入到我們當前的執行環境中…

不知不覺也碼了不少字了,開篇部分就先到這里吧,后面我繼續學習,在繼續更新吧~ :)


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com