国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

zepto源碼分析-代碼結(jié)構(gòu)

sherlock221 / 459人閱讀

摘要:本來想學(xué)習(xí)一下的源碼,但由于的源碼有多行,設(shè)計相當(dāng)復(fù)雜,所以決定從開始,分析一個成熟的框架的代碼結(jié)構(gòu)及執(zhí)行步驟。同時發(fā)表在我的博客源碼分析代碼結(jié)構(gòu)

本來想學(xué)習(xí)一下jQuery的源碼,但由于jQuery的源碼有10000多行,設(shè)計相當(dāng)復(fù)雜,所以決定從zepto開始,分析一個成熟的框架的代碼結(jié)構(gòu)及執(zhí)行步驟。

網(wǎng)上也有很多zepto的源碼分析,有的給源碼添加注釋,有的談與jQuery的不同,但是都沒有系統(tǒng)的講解zepto框架的代碼結(jié)構(gòu)及初始化Zepto對象的過程

準(zhǔn)備

默認(rèn)你已經(jīng)對面向?qū)ο笥幸欢ǖ牧私猓疚氖沁厡?shí)踐邊寫的,雖有些亂,但好處是為大家提供了分析的思路。

英文文檔、 中文文檔

注意在文中$變量表示一個函數(shù)對象,而$()表示執(zhí)行函數(shù),他會返回另一個對象。

從文檔入手分析$

在文檔中可以看到有兩類方法,其中一類是沒有$前綴,例如addClass,這些方法都有一個共同的特點(diǎn),操作DOM或BOM。還有一類是有前綴的例如$.trim,這一類方法無關(guān)平臺,只是封裝了一些常用的方法,可以看作ECMA層級的方法,與瀏覽器無關(guān)。

我們分別打印,看以下log日志




    
    Title


    

console.log($.prototype);
console.log($("#person"));
console.log($);


結(jié)果如上圖,展開綠色1即可看到所有前綴的方法,展開圖中2可看到所有的不帶前綴的方法。圖中3返回的是一個函數(shù)。

1中的結(jié)果可以看出像$.trim這類方法保存在$.prototype的構(gòu)造函數(shù)中,也就是在$中,但是$打印出來的是卻一個函數(shù),為了解決這中迷惑性,以下代碼重現(xiàn)了這種情況,可以看出,$確實(shí)是一個函數(shù),只是這個函數(shù)多了一些特定的方法。$.trim只是$的一個屬性。

2中的方法都在對象的原型函數(shù)中,因為它執(zhí)行了$()函數(shù)返回了一個對象Z,該對象的原型中包含一些類似于addClass方法。

var good = (function() {
  var g;
  var log = function(text){
    console.log(text);
  }
  g = function(){console.log("666");}
  g.log = log;
  return g;
})();
console.log(good.log("Are you OK?"));// Are you OK?
console.log(good);// function(){console.log("666");}

寫到這里突然想起來console對象還有個dir方法,console.dir($)清晰明了。-_-||
補(bǔ)充一張動圖

這種寫法的好處

我認(rèn)為這種寫法的好處有,調(diào)用$()后返回的對象是一個新對象,就沒有類似$.trim這類方法,且addClass這類方法都在原型函數(shù)中,更能節(jié)省內(nèi)存。

不執(zhí)行$函數(shù)對象,只是調(diào)用其函數(shù)中的特定屬性,該對象只會創(chuàng)建一次(在引入zepto時就已經(jīng)初始化了),同樣不會浪費(fèi)內(nèi)存。

兩種類型的方法共用同一個變量名,減少命名沖突的可能,封裝更徹底。

下面開始自上而下的分析源碼,層層剝離,使脈絡(luò)清晰。

一、閉包返回與全局變量
var Zepto = (function() {
  return $
})()

window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)

吐槽一下源碼中不寫分號,總感覺怪怪的。

使用自執(zhí)行匿名函數(shù)返回$傳遞給Zepto。然后把Zepto$作為window的屬性。

這樣對外只有兩個或一個變量可以使用,不會污染全局環(huán)境,如果命名沖突,只需改源碼中最后兩行即可。

二、核心架構(gòu)
var Zepto = (function() {
    var $,zepto = {};
    $.trim = function(str) {
        return str == null ? "" : String.prototype.trim.call(str)
    }
    $ = function(selector, context){
        return zepto.init(selector, context)
    }
    $.fn = {
        addClass: function(name){
            // 省略
        }
        // 省略
    }
    zepto.Z.prototype = Z.prototype = $.fn
    $.zepto = zepto
    return $
})()

在此可以看到$.trim與addClass與其他變量或?qū)傩缘年P(guān)系,去除這兩個屬性后就是第二層的架構(gòu),如下。

var $,zepto = {};

初始化了一個$變量和zepto對象,注意這里是小寫

$函數(shù)

這個函數(shù)調(diào)用zepto.init方法,返回對象,在之后會講解。

添加$.fn對象

它擁有Zepto對象上所有可用的方法(官方文檔),這里可能有誤解,應(yīng)該是擁有由$()返回的對象的所有方法,里面的方法在$("#person").prototype中看到過

zepto.Z.prototype = Z.prototype = $.fn

Z.prototype = $.fn如果你仔細(xì)觀察開始時的$("#person")返回的對象其實(shí)就是Z,那么經(jīng)過$()返回的對象的原型指向了擁有大量方法的$.fn對象,所以才可以在$("#person").prototype中看到過addClass方法

然后是zepto.Z.prototype = $.fn,請參考zepto源碼中關(guān)于zepto.Z.prototype = $.fn的問題

$.zepto = zepto

不知道為什么有這一句,似乎是可以通過$.zepto訪問內(nèi)部的方法,例如$.zepto.isZ($("#person"))。又或許是想將其封裝為$的屬性。

return $

可以清楚的看到內(nèi)部的結(jié)構(gòu),$.fn$.zepto$.trim都作為$對象的屬性存在,如果調(diào)用$()函數(shù),返回的Z對象就擁有指定的原型鏈Z.prototype = $.fn

那么問題又來了:zepto.init方法是做什么的?執(zhí)行$()函數(shù)返回的是什么對象?

三、框架的入口:zepto.init

還是先上源碼

$ = function(selector, context){
    return zepto.init(selector, context)
}
zepto.init = function(selector, context) {
    var dom
    if (!selector) return zepto.Z()// 如果是$()或$("")則執(zhí)行
    else if (typeof selector == "string") {// 如果傳入的是字符串
        selector = selector.trim()// 去除收尾空白符
        if (selector[0] == "<" && fragmentRE.test(selector))// 如果傳入的字符串是以<開頭且符合HTML代碼規(guī)則(用了正則表達(dá)式),即創(chuàng)建元素
            dom = zepto.fragment(selector, RegExp.$1, context), selector = null// 創(chuàng)建一個DOM對象
        else if (context !== undefined) return $(context).find(selector)// 這里其實(shí)是一種討巧的辦法,我相信jQuery中肯定不會這么寫,目的是實(shí)現(xiàn)在指定范圍內(nèi)查找[context]元素
        else dom = zepto.qsa(document, selector)// 調(diào)用zepto.qsa解析字符串,返回一個DOM數(shù)組
    }
    else if (isFunction(selector)) return $(document).ready(selector)// 很簡單,如果是函數(shù),則在文檔就緒后執(zhí)行
    else if (zepto.isZ(selector)) return selector// 如果是一個zepto對象,直接返回
    else {
        if (isArray(selector)) dom = compact(selector)// 如果是數(shù)組,調(diào)用compact返回一個數(shù)組,最后經(jīng)Z變成類數(shù)組對象,我想這里是把幾個DOM對象作為數(shù)組的參數(shù)傳入,返回一個類數(shù)組對象
        else if (isObject(selector))// 如果是一個對象,將其包含在數(shù)組之內(nèi),如p = document.getElementById("#p");$(p);
            dom = [selector], selector = null
        else if (fragmentRE.test(selector))// 不知道是干嘛的
            dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
        else if (context !== undefined) return $(context).find(selector)
        else dom = zepto.qsa(document, selector)
    }
    return zepto.Z(dom, selector)// 可以看這里,無論以上過程經(jīng)歷了什么,都要經(jīng)過此函數(shù),目的是將數(shù)組轉(zhuǎn)化為類數(shù)組對象。
}
zepto.Z = function(dom, selector) {
    return new Z(dom, selector)
}
/**
 * 一個構(gòu)造函數(shù),將dom對象中的屬性和方法都復(fù)制到this下,并添加了兩個屬性,length和selector,這個函數(shù)的目的是將DOM對象轉(zhuǎn)化為供zepto使用的類數(shù)組對象
 */
function Z(dom, selector) {
    var i, len = dom ? dom.length : 0
    for (i = 0; i < len; i++) this[i] = dom[i]
    this.length = len
    this.selector = selector || ""
}
zepto.fragment = function(html, name, properties) {
    // 這里的代碼就不展開了,其作用是返回一個DOM對象,若$()中傳入第二個參數(shù),則將其屬性添加給創(chuàng)建的DOM對象
    return dom
}
zepto.qsa = function(element, selector){
    // 這里也不展開代碼,又興趣的可以直接看源碼,很簡單,無非是根據(jù)傳入的選擇符分別調(diào)用getElementByID、getElementsByTagName、getElementsByClassName、querySelectorAll等方法,返回一個數(shù)組,數(shù)組的值即是DOM對象,這就是最核心的選擇器,有點(diǎn)坑爹。
}

這一段代碼是zepto的核心代碼,是使用zepto的入口,這里還是從文檔入手比較好理解。

Zepto集合是一個類似數(shù)組的對象,它具有鏈?zhǔn)椒椒▉聿僮魉赶虻腄OM節(jié)點(diǎn),除了$(Zepto)對象上的直接方法外(如$.extend),文檔對象中的所有方法都是集合方法。

上一句可以告訴我們:Zepto集合是一個類似數(shù)組的對象即是之前$("#person")返回的對象。文檔中所有不帶前綴的方法叫做集合方法

再來看方法的調(diào)用

$(selector, [context])      // 在指定范圍內(nèi)查找[context]元素,類似$(context).find(selector),例如$(".logo",".header"),只選取.header類中的.logo類
$()       // 這里應(yīng)該是指傳入zepto對象,如:var a = $("a");$(a);
$()              // 選取所有頁面中的div元素,如:$("div")
$(htmlString)               // 創(chuàng)建一個元素,如:$("

Hello

") $(htmlString, attributes) // 創(chuàng)建帶有屬性的元素,$("

", { text:"Hello", id:"greeting", css:{color:"darkblue"} }) Zepto(function($){ ... }) // 當(dāng)頁面ready的時候,執(zhí)行回調(diào) // 還有寫文檔中沒有 $()或$("")

至于為什么調(diào)用Z()函數(shù)返回的對象都以Z為對象名呢?看這段小代碼就可以明白

function Z(){
  this.name = 666;
}
z = new Z();
console.log(z);// 返回的對象名為Z

這個過程比較復(fù)雜,建議你親自動手試一試,還是以$("#person")為例,用Chrome在這一行打斷點(diǎn),然后步進(jìn),我看能不能做個flash圖。

如果你仔細(xì)觀察,這一層的核心源碼最后大部分都有return返回,最終$()也會返回對象,整個過程其實(shí)是對向$()中傳入的參數(shù)進(jìn)行處理運(yùn)算,最終返回一個zepto自己創(chuàng)造的對象,然后用于后續(xù)操作。

總結(jié)

zepto的源碼對一般的熟練面向?qū)ο蟮娜藖碚f是非常簡單的,對于有面向?qū)ο蟾拍顩]有寫過的人來說是那種踮起腳尖能得到的難度。最開始想學(xué)習(xí)jQuery源碼,但看了一點(diǎn)覺得太復(fù)雜,于是投機(jī)取巧看zepto,也是完全理不清頭緒啊,知道上個星期天找到了一種方法,寫一端小代碼,然后在Chrome里步進(jìn)調(diào)試,看函數(shù)之間的依賴關(guān)系法,看函數(shù)的傳入值,返回值,了解這個函數(shù)是做什么用的。最后慢慢的理清頭緒。這篇文章在星期一就開始寫,一直到星期四才算完成。

$(或Zepto)是一個函數(shù)對象,但他包含了一些特定的屬性(方法)。可以直接調(diào)用這些屬性(方法),這些屬性(方法)大都與瀏覽器無關(guān)。也可以執(zhí)行$函數(shù),執(zhí)行后返回一個類數(shù)組對象,這個對象的原型中包含一些操作DOM的方法,向原型中添加屬性(方法),所有的對象都可以訪問到。執(zhí)行$函數(shù)是zepto的關(guān)鍵代碼,其目的是根據(jù)傳入函數(shù)的變量值,加工處理成類數(shù)組對象并返回,用于后續(xù)操作。

同時發(fā)表在我的博客:《zepto源碼分析-代碼結(jié)構(gòu)》

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/80927.html

相關(guān)文章

  • Zepto源碼代碼結(jié)構(gòu)

    摘要:源碼結(jié)構(gòu)整體結(jié)構(gòu)如果在編輯器中將的源碼折疊起來,看到的就跟上面的代碼一樣。參考源碼分析代碼結(jié)構(gòu)對象思想與源碼分析設(shè)計和源碼分析源碼中關(guān)于的問題最后,所有文章都會同步發(fā)送到微信公眾號上,歡迎關(guān)注歡迎提意見 雖然最近工作中沒有怎么用 zepto ,但是據(jù)說 zepto 的源碼比較簡單,而且網(wǎng)上的資料也比較多,所以我就挑了 zepto 下手,希望能為以后閱讀其他框架的源碼打下基礎(chǔ)吧。 源碼版...

    warkiz 評論0 收藏0
  • Zepto 源碼分析 1 - 進(jìn)入 Zepto

    摘要:選擇的理由是一個用于現(xiàn)代瀏覽器的與大體兼容的庫。環(huán)境搭建分析環(huán)境的搭建僅需要一個常規(guī)頁面和原始代碼一個常規(guī)頁面打開的首頁即可,在開發(fā)人員工具中即可使用原始代碼本篇分析的代碼參照,進(jìn)入該代碼分支中即可。 選擇 Zepto 的理由 Zepto is a minimalist JavaScript library for modern browsers with a largely jQue...

    Aklman 評論0 收藏0
  • Zepto 源碼分析 4 - 核心模塊入口

    摘要:對象構(gòu)造函數(shù)讀入的兩個參數(shù)與在中也有明確的規(guī)范,用以保證構(gòu)造函數(shù)的簡單性。 承接第三篇末尾內(nèi)容,本篇結(jié)合官方 API 進(jìn)入對 Zepto 核心的分析,開始難度會比較大,需要重點(diǎn)理解幾個核心對象的關(guān)系,方能找到線索。 $() 與 Z 對象創(chuàng)建 Zepto Core API 的首個方法 $() 按照其官方解釋: Create a Zepto collection object by pe...

    xzavier 評論0 收藏0
  • Zepto源碼之Gesture模塊

    摘要:模塊基于上的事件的封裝,利用屬性,封裝出系列事件。這個判斷需要引入設(shè)備偵測模塊。然后是監(jiān)測事件,根據(jù)這三個事件,可以組合出和事件。其中變量對象和模塊中的對象的作用差不多,可以先看看讀源碼之模塊對模塊的分析。 Gesture 模塊基于 IOS 上的 Gesture 事件的封裝,利用 scale 屬性,封裝出 pinch 系列事件。 讀 Zepto 源碼系列文章已經(jīng)放到了github上,歡...

    coolpail 評論0 收藏0
  • Zepto 源碼分析 3 - qsa 實(shí)現(xiàn)與工具函數(shù)設(shè)計

    摘要:承接第一篇末尾內(nèi)容,本部分開始進(jìn)入主模塊,分析其設(shè)計思路與實(shí)現(xiàn)技巧下文代碼均進(jìn)行過重格式化,但代碼版本同第一部分內(nèi)容且入口函數(shù)不變的選擇器先從第一個與原型鏈構(gòu)造不直接相關(guān)的工具函數(shù)說起,觀察的設(shè)計思路。 承接第一篇末尾內(nèi)容,本部分開始進(jìn)入 zepto 主模塊,分析其設(shè)計思路與實(shí)現(xiàn)技巧(下文代碼均進(jìn)行過重格式化,但代碼 Commit 版本同第一部分內(nèi)容且入口函數(shù)不變): Zepto 的選...

    ctriptech 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<