這個(gè)部分是jquery一些常用的工具方法. 包括為jquery對(duì)象擴(kuò)展了一些數(shù)組里的方法.一些測(cè)試方法,函數(shù)代理和瀏覽器的特性檢測(cè).
數(shù)組和對(duì)象操作.這部分的很多方法都已經(jīng)成為javascript1.6的標(biāo)準(zhǔn). 這部分包括一些原型函數(shù),靜態(tài)函數(shù),內(nèi)部函數(shù). 原型函數(shù)主要通過(guò)api暴露給外界. 靜態(tài)方法主要包含了原型方法的具體邏輯實(shí)現(xiàn). 內(nèi)部函數(shù)主要供內(nèi)部調(diào)用. prototype上的方法一般設(shè)計(jì)得比較簡(jiǎn)單, 主要充當(dāng)一個(gè)控制層的作用. 而具體的實(shí)現(xiàn)邏輯, 大多數(shù)都放在了底層的靜態(tài)方法中. 這樣將來(lái)版本升級(jí)的時(shí)候, 一般只要修改靜態(tài)方法就可以了,跟api緊密耦合的prototype方法不會(huì)受到太多牽連. 這部分其中有一些方法已經(jīng)在jquery1.43源碼分析之核心部分寫(xiě)過(guò)了, 看看另外一些方法的實(shí)現(xiàn). jQuery.isArray
判斷對(duì)象是不是Array類型.這個(gè)簡(jiǎn)單的需求經(jīng)歷了漫長(zhǎng)的演變過(guò)程. 一般我們判斷對(duì)象類型, 會(huì)想到下面幾種方式. 1 typeof typeof 只能判斷大概區(qū)分是不是對(duì)象類型, 不論是Array還是Date還是null,還是通過(guò)自定義構(gòu)造函數(shù)生成的對(duì)象.返回的都是object 2 instanceof和constructor 都非常容易在原型繼承中出現(xiàn)問(wèn)題, 比如
而且在不同的iframe中, 判斷也不準(zhǔn)確, 因?yàn)椴煌膇frame不共享原型鏈. instanceof和constructor自然也會(huì)失效. 3 后來(lái)就有了流行一時(shí)的鴨式變型. 如果一只鴨子, 它會(huì)呱呱叫, 也會(huì)像鴨子一樣走路. 那么就認(rèn)為它就是鴨子.
不過(guò)也許有那么一只聰明的雞學(xué)會(huì)了呱呱叫, 也學(xué)會(huì)了像鴨子一樣走路. 比如 var a = {}; a.splice = 1; a.join = 2; 前面的方法顯然都不完美, 直到有個(gè)人發(fā)現(xiàn)了Object.prototype.toString.call(obj) === "[object Array]", 世界才變美好.其實(shí)就是利用toString方法來(lái)得到一個(gè)包含這個(gè)對(duì)象內(nèi)部屬性的字符串,這個(gè)字符串就包含了此對(duì)象構(gòu)造器的信息. jQuery.prototype.each 顧名思義, each方法是對(duì)數(shù)組或者對(duì)象中的每個(gè)元素都做一些類似的操作. 我們?cè)诳丛创a之前先自己實(shí)現(xiàn)一個(gè)Array.prototype.each.
很簡(jiǎn)陋, 然后想想它有哪些不足. 1, 在回調(diào)函數(shù)里我不知道當(dāng)前循環(huán)到了第幾個(gè)元素. 2, 回調(diào)函數(shù)里的this指向了window, 這個(gè)沒(méi)任何意義. 所以現(xiàn)在來(lái)稍微改一下.
現(xiàn)在在回調(diào)函數(shù)里可以取到3個(gè)值, this指向當(dāng)前元素. i表示循環(huán)到了第幾個(gè). n也表示當(dāng)前元素. 當(dāng)然你也可以把this指向別的東西. jquery就指向了原始元素. 不過(guò)如果我想在循環(huán)之中退出怎么辦, 比如我找到了2, 就想退出循環(huán).那么再修改一下.
現(xiàn)在已經(jīng)基本達(dá)到目的了, 再來(lái)看看jquery里each的實(shí)現(xiàn).
直接交給靜態(tài)方法jQuery.each來(lái)操作. 看看jQuery.each
其實(shí)each方法還有一個(gè)小小的缺陷. 當(dāng)要遍歷一個(gè)對(duì)象的時(shí)候. 比如 { name: "John", lang: "JS" }這個(gè)對(duì)象. 這樣寫(xiě)是沒(méi)問(wèn)題的.
但其實(shí)很多時(shí)候我們可能希望這樣寫(xiě)
但這樣寫(xiě)不行. 因?yàn)楝F(xiàn)在的目標(biāo)對(duì)象object實(shí)際上是一個(gè)經(jīng)過(guò)包裝了的jquery對(duì)象. 即使里面是單個(gè)元素, 它的length也為1. isObj為false. jquery不會(huì)遍歷它的屬性. 這個(gè)方法里的代碼其實(shí)也可以更精簡(jiǎn)一點(diǎn),2個(gè)大的條件分支完全可以合并成一個(gè). jQuery.prototype.map 將一組元素轉(zhuǎn)換成其他數(shù)組(不論是否是元素?cái)?shù)組) 其實(shí)很容易聯(lián)想到, map方法就是讓集合里的每個(gè)元素都執(zhí)行一次同一個(gè)函數(shù), 把返回值填充到一個(gè)數(shù)組并返回這個(gè)新的數(shù)組. 看個(gè)例子
ary已經(jīng)被轉(zhuǎn)化成為[4,5,6]. 再看源碼
看起來(lái)有一點(diǎn)點(diǎn)復(fù)雜, 其實(shí)callback.call( elem, i, elem )得到的是每個(gè)元素通過(guò)轉(zhuǎn)化之后的值.在jQuery.map里,這些值都會(huì)被填充進(jìn)一個(gè)新的數(shù)組.最后把原來(lái)的引用存入pushStack,方便回溯. 看看jquery.map
注意value != null, 這里只有2個(gè)等號(hào), 意味著可以也過(guò)濾掉返回值為undefined的元素, 比如在map一堆dom節(jié)點(diǎn)的子節(jié)點(diǎn)時(shí), 如果某個(gè)元素沒(méi)有子節(jié)點(diǎn), 那個(gè)元素就會(huì)被過(guò)濾掉. 可以看測(cè)試代碼
jQuery.prototype.grep 使用一個(gè)過(guò)濾函數(shù)閉包來(lái)按照某種條件來(lái)過(guò)濾數(shù)組
當(dāng)過(guò)濾函數(shù)的返回結(jié)果不為undefined, "", 0, false, null這5種情況之一時(shí), 通過(guò)!轉(zhuǎn)化恰好不等于默認(rèn)的inv(默認(rèn)為false). 條件成立,這個(gè)就是需要的元素. 不過(guò)一般情況下我們讓過(guò)濾函數(shù)返回true就可以了. 注意并沒(méi)有用callback.call的形式來(lái)調(diào)用callback. 所以callback里的this是指向window的. jQuery.prototype.ready 用來(lái)替代window.onload. 每個(gè)主流庫(kù)中都有這個(gè)方法的相應(yīng)實(shí)現(xiàn). 如果使用window.onload, 你必須得等到頁(yè)面的所有圖片,視頻等都加載完,才會(huì)觸發(fā)window.onload里面的方法. 下面是頁(yè)面加載的具體順序. onContentReady,這時(shí)DOM樹(shù)完成 script defer 這時(shí)開(kāi)始執(zhí)行設(shè)定了defer屬性的script. 某些庫(kù)比如ext用到了這個(gè)屬性 ondocumentready complete這時(shí)可以使用HTC組件與XHR html.doScroll 這時(shí)可以讓HTML元素使用doScroll方法 window.onload 這時(shí)圖片flash等資源都加載完畢 來(lái)自http://www.cnblogs.com/rubylouvre/archive/2009/12/30/1635645.html jQuery分別用到了onContentReady, html.doScroll, window.onload來(lái)確認(rèn)dom最早加載完成的時(shí)間. jQuery的實(shí)現(xiàn)可以大致分為這幾個(gè)步驟. 1首先把需要在頁(yè)面加載完成后執(zhí)行的函數(shù)都存到一個(gè)list中, 加載完成后再依次觸發(fā).并設(shè)置一個(gè)控制器, 保證一個(gè)頁(yè)面只有一個(gè)監(jiān)聽(tīng)函數(shù)在執(zhí)行. 2判斷document.readyState是不是為complete.表示dom是否加載完畢 3 如果2步驟失敗, 根據(jù)瀏覽器的不同,給document增加DOMContentLoaded或者onreadystatechange事件,當(dāng)該事件被觸發(fā)的時(shí)候執(zhí)行readyList里的方法. 4在IE瀏覽器中, 設(shè)置一個(gè)定時(shí)器,不停的查看是否已經(jīng)可以執(zhí)行這個(gè)操作.document.documentElement.doScroll("left");如果執(zhí)行這個(gè)操作時(shí)不再拋出異常,說(shuō)明dom已經(jīng)加載完畢了.這個(gè)辦法可能比步驟3更快. 看看代碼
這里的邏輯并不復(fù)雜, 當(dāng)調(diào)用$().ready(fn) 時(shí), 先通過(guò)jQuery.isReady看dom有沒(méi)有加載完成(jQuery.isReady默認(rèn)是false, 當(dāng)加載完成時(shí)會(huì)被設(shè)置為true).如果dom已經(jīng)加載完成了,就立刻執(zhí)行fn. 否則, 把fn添加進(jìn)待執(zhí)行的數(shù)組.等dom加載完成時(shí)再執(zhí)行. 看看bindReady的實(shí)現(xiàn)
再看看bindReady方法中涉及到的幾個(gè)方法.
doScrollCheck
jQuery.proxy proxy: function( fn, proxy, thisObject ) 返回一個(gè)新函數(shù),,這個(gè)函數(shù)的this指向你指定的對(duì)象. jquery1.4總算提供了this代理的方法了, 以前總是要自己實(shí)現(xiàn)一個(gè)Function.prototype.bind方法. 可能很多同學(xué)對(duì)this的調(diào)用和指向還是有點(diǎn)模糊. 那在此之前,先講一下this的幾種指向情況. 1 普通函數(shù)調(diào)用, this指向window. 比如 var fn = function(){ alert (this === window) }; fn(); 結(jié)果為true 2 對(duì)象屬性調(diào)用, this指向擁有這個(gè)屬性的對(duì)象. 比如 var obj = { fn: function(){ alert (this === obj); } obj.fn(); } 結(jié)果為true 或者 document.getElementById("id1").onclick = function(){ alert (this.id); } 點(diǎn)擊后彈出id1, 此時(shí)this指向onclick的擁有者id1. 3 通過(guò)構(gòu)造函數(shù)調(diào)用this時(shí),this指向通過(guò)構(gòu)造函數(shù)生成的對(duì)象. 比如 function A(){ this.b = 1; } var a = new A(); 當(dāng)a去調(diào)用A的構(gòu)造函數(shù)時(shí), this是指的a. 4 call或者apply, 這里的this是由自己指定. 比如
這里需要一個(gè)括號(hào)把function(){alert(this.name)}包圍起來(lái)是為了讓引擎把括號(hào)里面的語(yǔ)句當(dāng)成一個(gè)表達(dá)式而不是函數(shù)聲明, 函數(shù)聲明是不能調(diào)用方法的. 編譯期進(jìn)行語(yǔ)法檢測(cè)的時(shí)候就會(huì)報(bào)錯(cuò). 其實(shí)我們?cè)陂_(kāi)發(fā)很容易就不知不覺(jué)弄丟了this.舉個(gè)例子.我要點(diǎn)擊一個(gè)div的時(shí)候,彈出這個(gè)div的id.
這個(gè)方法里的this就已經(jīng)是window了. 一般我們可以改成這樣
也許你不喜歡self這個(gè)臨時(shí)變量.那換一種方法.我們擴(kuò)展一下Function的原型,實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的bind方法.
現(xiàn)在已經(jīng)OK了,沒(méi)有了討厭的臨時(shí)變量. 這里的proxy方法肯定也是利用call或者apply方法來(lái)指定this. 看看api上的例子
proxy根據(jù)參數(shù)傳遞的不同有2種調(diào)用方式, 1, 參數(shù)分別為obj對(duì)象, 被代理函數(shù)(必須是obj對(duì)象的屬性). 結(jié)果是返回obj.test函數(shù), this指向obj. 2, 參數(shù)分別為被代理函數(shù)(obj.test), this指向obj. 第二種方式看來(lái)順眼得多.再看看源碼的具體實(shí)現(xiàn)
瀏覽器特性檢測(cè) 從jquery1.3版本開(kāi)始, 寫(xiě)不同瀏覽器的兼容代碼之前, 不贊成再去判斷瀏覽器的類型, 而是直接判斷支不支持某個(gè)特性, 比如盒模型. 透明度這些. 就像一個(gè)老外向你問(wèn)路的時(shí)候, 他肯定是先說(shuō)can you speak English. 而不是are you Amercan. 關(guān)于特性檢測(cè)的具體實(shí)現(xiàn), 可以參考下面文章. http://peter./articles/feature-detection-state-of-the-art-browser-scripting http://yura./cft/ http://www./faq/faq_notes/not_browser_detect.html |
|
來(lái)自: quasiceo > 《javascript》