1. 程式人生 > >【jquery學習筆記】美元背後的一點小技巧

【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物件,該物件特徵如下:

  1. 擁有一個length屬性,length等於你呼叫$選中的元素的數目,在$('#casper')中為1
  2. 擁有0~n-1的例項屬性,分別對應呼叫$時選中的第1~第n個元素,如本例中$('#casper')[0]即為目標dom元素
  3. 擁有一堆原型方法,如常見的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 $)) ,作用在於判斷,當$被呼叫時,究竟是採用以下兩種呼叫方式的哪一種,關於這種判斷方式,可參考之前寫的《【經驗總結】建構函式的強制呼叫》

  1. $('casper'),直接呼叫,於是this為window
  2. 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。。。

上面只是開個小玩笑,繞了這麼久,無法是想做下面幾件事情:

  1. 無論有沒有new,只要呼叫$,都給你返回一個jQuery物件(實際上jQuery.fn.init才是實際的建構函式)
  2. 將jQuery.fn.init.fn指向jQuery.prototype,這樣的話,當我們通過$.fn.newPrototypeAttr 方式向jQuery新增原型屬性或方法,其實最終都成為了jQuery.fn.init地原型屬性或方法
  3. 將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 表名:查看表結構