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

資訊專欄INFORMATION COLUMN

zepto源碼分析-代碼結構

sherlock221 / 468人閱讀

摘要:本來想學習一下的源碼,但由于的源碼有多行,設計相當復雜,所以決定從開始,分析一個成熟的框架的代碼結構及執行步驟。同時發表在我的博客源碼分析代碼結構

本來想學習一下jQuery的源碼,但由于jQuery的源碼有10000多行,設計相當復雜,所以決定從zepto開始,分析一個成熟的框架的代碼結構及執行步驟。

網上也有很多zepto的源碼分析,有的給源碼添加注釋,有的談與jQuery的不同,但是都沒有系統的講解zepto框架的代碼結構及初始化Zepto對象的過程

準備

默認你已經對面向對象有一定的了解,本文是邊實踐邊寫的,雖有些亂,但好處是為大家提供了分析的思路。

英文文檔、 中文文檔

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

從文檔入手分析$

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

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




    
    Title


    

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


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

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

2中的方法都在對象的原型函數中,因為它執行了$()函數返回了一個對象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($)清晰明了。-_-||
補充一張動圖

這種寫法的好處

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

不執行$函數對象,只是調用其函數中的特定屬性,該對象只會創建一次(在引入zepto時就已經初始化了),同樣不會浪費內存。

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

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

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

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

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

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

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

二、核心架構
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與其他變量或屬性的關系,去除這兩個屬性后就是第二層的架構,如下。

var $,zepto = {};

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

$函數

這個函數調用zepto.init方法,返回對象,在之后會講解。

添加$.fn對象

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

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

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

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

$.zepto = zepto

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

return $

可以清楚的看到內部的結構,$.fn$.zepto$.trim都作為$對象的屬性存在,如果調用$()函數,返回的Z對象就擁有指定的原型鏈Z.prototype = $.fn

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

三、框架的入口:zepto.init

還是先上源碼

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

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

Zepto集合是一個類似數組的對象,它具有鏈式方法來操作它指向的DOM節點,除了$(Zepto)對象上的直接方法外(如$.extend),文檔對象中的所有方法都是集合方法。

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

再來看方法的調用

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

Hello

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

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

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

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

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

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

總結

zepto的源碼對一般的熟練面向對象的人來說是非常簡單的,對于有面向對象概念沒有寫過的人來說是那種踮起腳尖能得到的難度。最開始想學習jQuery源碼,但看了一點覺得太復雜,于是投機取巧看zepto,也是完全理不清頭緒啊,知道上個星期天找到了一種方法,寫一端小代碼,然后在Chrome里步進調試,看函數之間的依賴關系法,看函數的傳入值,返回值,了解這個函數是做什么用的。最后慢慢的理清頭緒。這篇文章在星期一就開始寫,一直到星期四才算完成。

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

同時發表在我的博客:《zepto源碼分析-代碼結構》

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/80927.html

相關文章

  • Zepto源碼代碼結構

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

    warkiz 評論0 收藏0
  • Zepto 源碼分析 1 - 進入 Zepto

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

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

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

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

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

    coolpail 評論0 收藏0
  • Zepto 源碼分析 3 - qsa 實現與工具函數設計

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

    ctriptech 評論0 收藏0

發表評論

0條評論

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