【jquery學習筆記】美元背後的一點小技巧
寫在前面:本文比較基礎,僅是一枚菜鳥接觸jquery過程中的一點思考和總結,內容較基礎,希望能對剛接觸jQuery的童鞋有一點幫助 :)
按照國際慣例(其實就是俺寫作的習慣),首先丟擲待問題的場景。至於問題的答案,文章並不會急著揭曉,而是通過逐層遞進的方式,展現思考、解決一個問題的過程
1、如何給一個id為casper的標籤新增一個名為“world”的class
考慮下面一個場景,假設我們頁面上有個id為casper的div標籤,如下所示
<div id="casper" class="hello">casper是個大傻瓜,啦啦啦啦啦</div>
現在我們想要給它新增一個class,比如“world”,用jquery的話如何實現?很簡單,不賣關子
$('#casper').addClass('world');
很好,接下來我們思考:如何不用jquery,我們如何如何實現實現上述功能?最簡單的方式:
var node = document.getElementById('casper'); node.className += ' world';
getElementById、getElementsByTagName神馬的,名字老長老長的,寫著有點不爽,於是把getElementById這個方法用美元($)包裝下:
function $(id){ return document.getElementById(id); }
$('casper').className += ' world';
className品字串神馬的,jquery的呼叫方式相比麻煩多了,那再改進下:
function $(id){ var node = document.getElementById(id); node.addClass = function(addName){ node.className += ' ' + addName; }; return document.getElementById(id); } $('casper').addClass('world');
看上去挺像那麼一回事了,多優雅的介面啊(熱淚盈眶中)~
真的是這樣嗎,再仔細瞧瞧?於是果斷髮現不對勁的地方:對於$,每次呼叫,都會給返回的dom元素上新增一個addClass方法,這對空間來說是極大的浪費。當然,可以將addClass方法抽取出來:
function addClass(className){ //實現略 } function $(id){ var node = document.getElementById(id); node.addClass = addClass; return document.getElementById(id); } $('casper').addClass('world');
原先的空間浪費問題可以在很大程度上得到解決,但明顯這解決方法還不夠好。如果有那麼一種實現方式,讓所有的物件例項都共享一個方法。。。
2、jQuery中的實現思路
同樣不必賣關子,這裡說的就是原型方法,我們再看下jquery的呼叫方式
$('#casper').addClass('world');
$('#casper')並不是像我們上面那樣,簡單地將id為casper的元素返回。實際上,$('#casper')返回的是一個jQuery物件,該物件特徵如下:
- 擁有一個length屬性,length等於你呼叫$選中的元素的數目,在$('#casper')中為1
- 擁有0~n-1的例項屬性,分別對應呼叫$時選中的第1~第n個元素,如本例中$('#casper')[0]即為目標dom元素
- 擁有一堆原型方法,如常見的addClass、removeClass、bind等
根據上面三點,很容易對我們之前寫的程式碼進行修改,如下:
function $(id){ this[0] = document.getElementById(id); this.length = 1; } $.prototype.addClass = function(className){ this[0].className += ' ' + className; }; var noode = new $('casper'); node.addClass('world');
其實就幾行程式碼的事情,但。。。還是覺得有些不對勁,new $('casper'),平常在用jquery的時候似乎不需要new一下的說,想想看,我們程式碼中一坨new是多麼可怕的事情~
好吧,其實是因為jQuery幫你完成了建構函式呼叫的這部分工作,這一小小的細節改善對jQuery的流行起到了很大的幫助。按照這個思路,繼續修改之前的程式碼:
function $(id){ if(!(this instanceof $) return new $(id); //加了這麼個語句 this[0] = document.getElementById(id); this.length = 1; }
//其他一樣,節省空間不貼程式碼
在上面的程式碼中,只有一點小小的修改,就是加了個判斷語句 if(!(this instanceof $)) ,作用在於判斷,當$被呼叫時,究竟是採用以下兩種呼叫方式的哪一種,關於這種判斷方式,可參考之前寫的《【經驗總結】建構函式的強制呼叫》:
- $('casper'),直接呼叫,於是this為window
- new $('casper'),此時$為構造方法,this instanceof $ == true
3、jQuery中的原始碼實現以及問題所在(俺的疑惑)
羅嗦了這麼多,我們看看關於這點,jQuery裡是如何實現的,原始碼大致如下,一些不相干的程式碼略過:
(function( window, undefined ) { //去掉無關變數宣告等,防止干擾分析 var jQuery = (function() { // Define a local copy of jQuery var jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' return new jQuery.fn.init( selector, context, rootjQuery ); }, //一堆無關細節暫時略過 jQuery.fn = jQuery.prototype = { constructor: jQuery, init: function( selector, context, rootjQuery ) { //繼續略過 } }; // Give the init function the jQuery prototype for later instantiation jQuery.fn.init.prototype = jQuery.fn; return jQuery; })(); window.jQuery = window.$ = jQuery; })( window );
對於研究過jQuery原始碼或曾經打算研究jQuery原始碼的同學來說,上面這段程式碼肯定不會陌生,它有一個特點:看上去比較晦澀,特別是是結合了jQuery原始碼裡面比較詭異的程式碼縮排~
通過閉包返回的jQuery物件,閉包裡面是有jQuery函式定義,jQuery函式裡面return了new jQuery.fn.init 。。。快速看懂上面這段程式碼的祕訣在於:一個支援程式碼高亮和職能中括號匹配的編輯器,比如webstorm。。。
上面只是開個小玩笑,繞了這麼久,無法是想做下面幾件事情:
- 無論有沒有new,只要呼叫$,都給你返回一個jQuery物件(實際上jQuery.fn.init才是實際的建構函式)
- 將jQuery.fn.init.fn指向jQuery.prototype,這樣的話,當我們通過$.fn.newPrototypeAttr 方式向jQuery新增原型屬性或方法,其實最終都成為了jQuery.fn.init地原型屬性或方法
- 將constructor屬性指向jQuery,不然$('#casper').constructor 獲得的會是jQuery.fn.init
個人覺得上面這段程式碼有些費解,似乎完全可以採用相對不那麼曲折的方式實現,如下所示,其實思路都是相同的:
然後,就是新增各種原型方法了,相容性處理和優雅的API,這塊才是精華,這裡還沒講到。
(function(){ var jQuery = function(id){ return new _jquery(id); }; var _jquery = function(id){ //此處各種選擇分支神馬的都忽略~ this[0] = document.getElementById(id); this.length = 1; }; jQuery.fn = jQuery.prototype = { constructor: jQuery, addClass: function(className){ this[0].className += ' ' + className; } }; _jquery.prototype = jQuery.fn; window.$ = window.jQuery = jQuery; })();
相關推薦
【jquery學習筆記】美元背後的一點小技巧
寫在前面:本文比較基礎,僅是一枚菜鳥接觸jquery過程中的一點思考和總結,內容較基礎,希望能對剛接觸jQuery的童鞋有一點幫助 :) 按照國際慣例(其實就是俺寫作的習慣),首先丟擲待問題的場景。至於問題的答案,文章並不會急著揭曉,而是通過逐層遞進的方式,展現思考、解決一個問題的過程 1、如何給一個id
【jQuery學習筆記-----jQuery事件名稱空間】
jQuery事件名稱空間 jQuery支援事件名稱空間,以方便事件管理。例如,在下面的示例中,為div元素繫結多個事件型別,然後使用名稱空間進行規範,從而方便管理。所謂事件名稱空間,就晨事件型別後面以點語法附加一個別名,以便引用事件,如”click.a”,其中”a”就是cl
【JAVAWEB學習筆記】12_Http&Tomcat
請求重定向 san res tor tomcat啟動 zha rac pac b- 一、Http協議 1.什麽是Http協議 HTTP,超文本傳輸協議(HyperText Transfer Protocol)是互聯網上應用最為廣泛的 一種網絡協議。所有的WWW文
【extjs6學習筆記】1.1 初始:創建項目
workspace 學習 分享 pps cnblogs log -i 學習筆記 apps 創建工作空間 sencha generate workspace /path/to/workspace 使用sencha創建應用 sencha
【extjs6學習筆記】1.2 初始:MVC MVVM
控制 進行 nbsp 例如 ges 如果 image 初始 互動 模型 這表示數據層。該模型可以包含數據驗證和邏輯來保持數據。在 ext js 中, 大多數模型都與一個數據存儲一起使用。 視圖 這表示用戶界面。 是用戶在屏幕上看到的組
【JAVAWEB學習筆記】13_servlet
eight 生命周期 sys blog source con 相對 對象創建 功能 JavaWeb核心之Servlet 教學導航 學習目標: 案例一、完成用戶登錄功能 案例二、記錄成功登錄系統的人次 一、Servlet簡介 1.什麽是Servlet Servlet
【JAVAWEB學習筆記】16_session&cookie
發送 學習筆記 獲得 tab esp http 應用 區分 pac 會話技術Cookie&Session 學習目標 案例一、記錄用戶的上次訪問時間---cookie 案例二、實現驗證碼的校驗----session 一、會話技術簡介 1.存儲客
【JAVAWEB學習筆記】23_Listener和郵箱服務器
添加 .get 接收 監聽 lin 感知 一個 rate 包括 監聽器Listener 學習目標 案例-使用監聽器完成定時生日祝福 一、監聽器Listener javaEE包括13門規範 在課程中主要學習 servlet技術 和 jsp技術 其中
【extjs6學習筆記】0.1 準備:基礎概念(02)
json over cal 類的屬性 tab 常用事件 data 微軟 基於 Ext 類 Ext 是一個全局單例的對象,在 Sencha library 中它封裝了所有的類和許多實用的方法。許多常用的函數都定義在 Ext 對象裏。它還提供了像其他類中一些頻繁使用的方法
【extjs6學習筆記】1.7 初始:加載第三方庫
sum pro eve owa spec expect mapview cap ply https://www.sencha.com/blog/integrating-ext-js-with-3rd-party-libraries-2/ Introduction
【JAVAWEB學習筆記】22
ont 交換 開發 異步校驗 什麽是 zhang add 一個 url Js原生Ajax和Jquery的Ajax 學習目標 案例1-異步校驗用戶名是否存在 案例2-站內查詢 一、Ajax概述 1.什麽是同步,什麽是異步 同步現象:客戶端發送請
【JAVAWEB學習筆記】17
lose 常用屬性 註釋 作用 enter tps img 客戶 mage 動態頁面技術(JSP/EL/JSTL) 學習目標 案例:完成商品的列表的展示 一、JSP技術 1.jsp腳本和註釋 jsp腳本: 1)<%java代碼%> -
【extjs6學習筆記】1.9 初始: Mixins
另一個 筆記 extjs 微軟 mage extjs6 名稱 img pan Mixin允許我們使用一個類的函數作為另一個類的函數而不繼承。 Mixins可以使用mixins關鍵字定義,並將值指定為JSON對象,其中屬性的名稱應該是要使用的方法的名稱,屬性的值
【JAVAWEB學習筆記】09
like 筆記 關聯關系 server enc put logs 問題 dir 今天晨讀單詞: order:訂單constraint:(強制)約束foreign key:外鍵references:指向orderitem:訂單項join:加入resourceBundle:資源
【JAVAWEB學習筆記】04
文件 使用 ava back move 比較 nload 索引 方式 晨讀單詞: onmouseover:鼠標移入 onmouseout:鼠標移出 attribute:屬性 node:節點 document:文檔 element:元素 textNode:文本節點 appen
【JAVAWEB學習筆記】01
顏色 col 文本 鏈接 target sel nbsp html標簽 劃線 案例一:網站信息顯示頁面1.什麽是HTML?(Hyper Text Markup Language:超文本標記語言)超文本:功能比普通文本更加強大標記語言:使用一組標簽對內容進行描述的一門語言(它
【JAVAWEB學習筆記】23
clear 定時 tab 都沒有 cal subject 優化 select 再次 監聽器Listener 學習目標 案例-使用監聽器完成定時生日祝福 一、監聽器Listener javaEE包括13門規範 在課程中主要學習 servlet技術
【extjs6學習筆記】1.10 初始: 定義類
ria nbsp src clas -1 學習 ref 定義類 mage http://www.extjs-tutorial.com/extjs/define-new-class-in-extj
【JAVAWEB學習筆記】03
參數 get undefined onload string href ber tor war javascript簡單介紹 ECMAScript 1.語法 2.變量:只能使用var定義,如果在函數的內容使用var定義,那麽它是一個局部變量,如果沒有使用var它是一個全
【JAVAWEB學習筆記】08
lob 加載驅動 控制 class 並且 tint 單元測試junit 最大 類對象 今天晨讀單詞: CRUD:增刪改查(create/read/update/delete)create:新增項目read:查詢update:修改delete:刪除 desc 表名:查看表結構