jQuery對於大家而言並不陌生,因此關於它是什麼以及它的作用,在這裡我就不多言了,而本篇文章的目的是想透過對源碼簡單的分析來討論jQuery 的核心架構設計,以及jQuery 是如何利用javascript中的高階特性來建立如此偉大的javascript函式庫。
1 初識jQuery
從核心功能來看,jQuery僅僅做了一件簡單而又平凡的事:查詢。它的文法如此簡潔明了,以致於很多人在不知道javascript是什麼的時候就已經會用jQuery了,用一個字形容就是:大道至簡。 從設計層面來看,我們可以將jQuery提供方法分為兩大類:靜態方法和實例方法。靜態方法就是直接透過$存取的方法,這些方法一般不對dom元素操作,而是提供了一些常用的工具,例如ajax請求、以及對字串的一些常用操作,除此之外,jQuery還提供了對自身的擴充機制,你可以透過extend方法來寫你需要的元件。而實例方法和靜態方法不一樣,它是用來對jQuery查詢的DOM元素進行操作,jQuery執行$()會建構一個jQuery對象,這個對像以數組的方法存儲查詢出的所有DOM元素,然後在這個在物件的原型鏈上實作了對這些DOM操作的方法,例如each()方法就是用來遍歷每一個DOM元素的。你可能會注意到,我只是說這個物件「以數組的方式」存儲,那就是說,jQuery建構的這個物件不是數組,那這個物件到底是什麼? 其實這個物件就是jQuery的核心,也被稱為「jQuery物件」。因此,本文的重點就是對jQuery物件進行分析與討論。
2 jQuery物件
一般情況下,我們會這樣使用jQuery:
$('div').each(function(index){ //this ...});
$('div')執行完後回傳一個jQuery物件,each()是對這個物件中的方法是對這個物件中的方法元素進行遍歷,我們先來看看$('div')的執行過程(本文源碼摘自jQuery 3.0):
jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context ); }
這個方法就是$('div')的入口方法,$是jQuery的簡寫,就相當於jQuery('div') ,可以看出,這個方法只做了一件事,那就是返回jQuery.fn.init()函數的實例對象,那jQuery.fn.init 又是什麼呢,我們再看下面的程式碼:
init = jQuery.fn.init = = jQuery.fn;
jQuery.fn.init和init引用了同一個方法,這個方法根據selector查詢出符合條件的DOM元素,並返回,可你會發現,返回的是this,這個this是什麼呢?我們待會分析,先看下面的這句話:
init.prototype = jQuery.fn;
這句話是什麼意思呢,這句話是讓init方法的prototype對象指向了jQuery.fn對象,那jQuery.fn又是什麼鬼? 我們繼續看程式碼:
jQuery.fn = jQuery.prototype = { // The current version of jQuery being used jquery: version, constructor: jQuery, // The default length of a jQuery object is 0 length: 0, // Execute a callback for every element in the matched set. each: function( callback ) { return jQuery.each( this, callback ); }, splice: arr.splice };
為了節省篇幅,我省略了其中一些程式碼,從這裡可以看出,jQuery.fn 其實就是jQuery的原型對象,這個原型物件中定義了一些對this對象進行操作的方法。到這裡,你是不是感覺到有點繞,不要著急,我們來梳理一下思路:jQuery首先定義了一個init方法,然後在init的原型對象prototype上定義了一系列操作方法。最後將init方法的實例物件傳回。所以上面的過程可以簡化如下(偽代碼表示):
var init = function(selector,context,root){ //... return this; } init.prototype = { length:0, each:function(callback){ //... }, splice:[].splice } jQuery = function(selector,context,root){ return new init(selector,context,root); }
那麼問題來了,jQuery.fn中的方法為什麼不直接定義在init的prototype上,而要定義在jQuery的原型對像上?
其實,這樣做的目的是為了提高jQuery的查詢效率,如果直接定義在init的prototype對像上,那麼每執行一次查詢,就會在內存中創建這樣一個龐大的prototype對象,而如果把這個對象定義在jQuery的prototype上,在jQuery載入時,這個物件就會被初始化並且一直存在於記憶體中,以後每次執行$()時,只需要將init中的prototype指向這個物件就可以了,而不用每次都去創建一遍相同的物件。
我們再來看看 init 函數中回傳的 this 到底是什麼,我在之前的部落格中講過,函數中的this總是指向運行期的呼叫者,那init的呼叫者是誰呢?在上面程式碼中似乎找不到呼叫者,這時我們就需要深入的理解new運算子的運作機制了,借用我之前在部落格中對new運算子的描述,我們對new init()的執行過程進行如下分解:
new init(selector,context,root) = { var obj = {}; obj.__proto__ = init.prototype; init.call(obj,selector,context,root); return typeof result === 'obj'? result : obj; }
從上述分解過程可以看出,javascript在透過new 來創建一個實例對象的時候,會先創建了一個普通對象obj,然後將obj的內部屬性__proto__指向了init的原型對象,因此obj的原型鏈將被改變,而第3步使用call方法呼叫init(),所以init中的this指的就是這裡的obj物件。
init()執行以後,會將匹配到的所有DOM對像以數組的方式存儲到this對像中並返回,也就是返回了obj對象,而new運算符最終也會將這個obj 對象返回以作為新的實例物件。 所以new運算子回傳的這個實例物件具備兩個特點:一是包含了DOM查詢結果集,二是其原型鏈繼承了init的prototype,而init 的prototype 又指向了jQuery.fn對象,因此實例對象也具備了這些操作方法。
jQuery每執行一次查詢就會建立一個jQuery對象,而在同一個應用程式中,所有jQuery物件都會共用同一個jQuery原型物件。因此,jQuery物件不僅包含了DOM查詢結果集,也繼承了jQuery原型物件上的操作方法。這樣,你就可以在查詢後直接呼叫方法來操作這些DOM元素了。這就是jQuery的核心架構設計,簡單、方便、實用!
如果你還不理解上面的講解,不要著急,我按照jQuery的設計思路寫了一個完整的小項目jDate,你可以對比著理解! jDate專案已上傳至GitHub,你可以點擊這裡查看完整程式碼:jDate ,如有不同見解,歡迎討論!
3 jQuery 的缺陷
透過對jQuery的核心架構分析,我們會發現,每執行一次查詢,jQuery就要在內存中構建一個複雜的jQuery對象,雖然說每個jQuery對像都共享同一個jQuery原型,但jQuery的查詢過程遠比你想像的要複雜,它既要考慮各種不同的匹配標識,同時又要考慮不同瀏覽器的兼容性。因此,如果你只是對DOM做一些簡單的操作,建議使用原生方法querySelector 替代jQuery,不過在使用原生方法時,對於不同的應用場景你可能要做一些兼容性的工作,你要學會取捨,不要過度依賴jQuery!

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

SublimeText3 Linux新版
SublimeText3 Linux最新版

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。