Zepto源碼分析,zepto源碼

來源:互聯網
上載者:User

Zepto源碼分析,zepto源碼
今天抽空複習了一下Zepto的源碼,按照自己的理解進行注釋。歡迎大家拍磚。源碼版本:v1.1.4源碼:http://zeptojs.com/
分析整體代碼之後,整理出架構圖:

本次只針對擷取核心方法$()進行撥離,並用demo測試api。

var Zepto = (function() {    // 變數初始化    var $;    var zepto = {};    var fragmentRE = /^\s*<(\w+|!)[^>]*>/;    var singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;    var tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig;    var undefined;    var emptyArray = [];    var slice = emptyArray.slice;    var cssNumber = {        'column-count': 1,        'columns': 1,        'font-weight': 1,        'line-height': 1,        'opacity': 1,        'z-index': 1,        'zoom': 1    };    // 特殊屬性集合    var methodAttributes = [ 'val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset' ];    var table = document.createElement('table');    var tableRow = document.createElement('tr');    var containers = {        'tr': document.createElement('tbody'),        'tbody': table,        'thead': table,        'tfoot': table,        'td': tableRow,        'th': tableRow,        '*': document.createElement('div')    };    var readyRE = /complete|loaded|interactive/;    var simpleSelectorRE = /^[\w-]*$/;    var class2type = {};    var toString = class2type.toString;    var isArray = Array.isArray || function(object) {        return object instanceof Array;    };    function type(obj) {        return obj == null ? String(obj) : class2type[toString.call(obj)] || "object";    }    function isFunction(value) {        return type(value) == "function";    }    function isWindow(obj) {        return obj != null && obj == obj.window;    }    function isDocument(obj) {        return obj != null && obj.nodeType == obj.DOCUMENT_NODE;    }    function isObject(obj) {        return type(obj) == "object";    }    function isPlainObject(obj) {        return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype;    }    function likeArray(obj) {        return typeof obj.length == 'number';    }    function dasherize(str) {        return str.replace(/::/g, '/')            .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')            .replace(/([a-z\d])([A-Z])/g, '$1_$2')            .replace(/_/g, '-')            .toLowerCase()    }    function maybeAddPx(name, value) {        return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value;    }    /**     * `$.zepto.fragment`需要一個html字串和一個可選標記名來產生dom     * 產生的dom返回一個數組形式     * 該功能可以被外掛程式覆蓋     * 沒有覆蓋所有瀏覽器     */    zepto.fragment = function(html, name, properties) {        var dom;        var nodes;        var container;        // 標籤特殊化處理        if (singleTagRE.test(html)) {            dom = $(document.createElement(RegExp.$1));        }        if (!dom) {            if (html.replace) {                html = html.replace(tagExpanderRE, "<$1></$2>");            }            if (name === undefined) {                name = fragmentRE.test(html) && RegExp.$1;            }            if (!(name in containers)) {                name = '*';            }            container = containers[name];            container.innerHTML = '' + html;            dom = $.each(slice.call(container.childNodes), function() {                container.removeChild(this);            });        }        if (isPlainObject(properties)) {            nodes = $(dom);            $.each(properties, function(key, value) {                if (methodAttributes.indexOf(key) > -1) {                    nodes[key](value);                } else {                    nodes.attr(key, value);                }            });        }        return dom;    };    /**     * `$.zepto.Z`將給定`dom`節點數組的原型賦上`$.fn`提供的所有Zepto函數     * 請注意,`__proto__`不支援IE瀏覽器     */    zepto.Z = function(dom, selector) {        dom = dom || [];        dom.__proto__ = $.fn;        dom.selector = selector || '';        return dom;    };    // `$.zepto.isZ`檢查給定的對象是一個Zepto的集合,可被外掛程式覆蓋    zepto.isZ = function(object) {        return object instanceof zepto.Z;    };    /**     * `$.zepto.init`是Zepto借鑒jQuery的`$.fn.init`     * 採用css選取器和一個可選的上下文(處理各種特殊情況)     * 該方法可被外掛程式覆蓋     */    zepto.init = function(selector, context) {        // 如果沒有給出,返回一個空的Zepto集合        if (!selector) {            return zepto.Z();        // 檢測字串類型        } else if (typeof selector == 'string') {            selector = selector.trim();            /**             * 如果是一個HTML片段,建立節點注意,在chrome21和FF15版本,             * DOM錯誤12不是以<被拋出             */            if (selector[0] == '<' && fragmentRE.test(selector)) {                dom = zepto.fragment(selector, RegExp.$1, context);                selector = null;            }            // 如果存在一個上下文環境,建立收集,並從中選擇節點            else if (context !== undefined) {                return $(context).find(selector);            }            // 如果是一個css選取器,用它來選擇節點            else {                dom = zepto.qsa(document, selector);            }        }        // 如果一個函數存在,在domready就緒後觸發        else if (isFunction(selector)) {            return $(document).ready(selector);        }        // 如果zepto已經收集給出,直接返回        else if (zepto.isZ(selector)) {            return selector;        }        else {            // 如果節點已經為數組,進行彙總            if (isArray(selector)) {                dom = compact(selector);            }            // 封裝DOM節點            else if (isObject(selector)) {                dom = [selector];                selector = null;            }            // 如果是一個HTML片段,對該片段建立節點            else if (fragmentRE.test(selector)) {                dom = zepto.fragment(selector.trim(), RegExp.$1, context);                selector = null;            }            // 如果存在上下文環境,先建立收集,並從中選擇節點            else if (context !== undefined) {                return $(context).find(selector);            }            // 如果是一個css選取器,用它來選擇節點            else {                dom = zepto.qsa(document, selector);            }        }        // 對發現的節點建立一個新的Zepto集合        return zepto.Z(dom, selector);    };    // `$`作為Zepto的元對象,當調用`$`該函數將轉由`$.zepto.init`處理    $ = function(selector, context) {        return zepto.init(selector, context);    };    /**     * `$.zepto.qsa`是Zepto的css選取器,使用document.querySelectorAll及特殊情況處理     * 可被外掛程式覆蓋     */    zepto.qsa = function(element, selector) {        var found;        var maybeID = (selector[0] == '#');        var maybeClass = !maybeID && selector[0] == '.';        // 確認下標從1開始後的字元名        var nameOnly = maybeID || maybeClass ? selector.slice(1) : selector;        var isSimple = simpleSelectorRE.test(nameOnly);        return (isDocument(element) && isSimple && maybeID) ?            ((found = element.getElementById(nameOnly)) ? [found] : []) :            (element.nodeType !== 1 && element.nodeType !== 9) ? [] :            slice.call((isSimple && !maybeID) ?                maybeClass ? element.getElementsByClassName(nameOnly) : //class名稱                element.getElementsByTagName(selector) : // tag名稱                element.querySelectorAll(selector) // 查詢所有匹配到的            );    };    function setAttribute(node, name, value) {        value == null ? node.removeAttribute(name) : node.setAttribute(name, value);    }    // 函數參數    function funcArg(context, arg, idx, payload) {        return isFunction(arg) ? arg.call(context, idx, payload) : arg;    }    $.type = type;    $.isFunction = isFunction;    $.isWindow = isWindow;    $.isArray = isArray;    $.isPlainObject = isPlainObject;    // Zepto對象迭代器    $.each = function(elements, callback) {        var i;        var key;        if (likeArray(elements)) {            for (i = 0; i < elements.length; i++) {                if (callback.call(elements[i], i, elements[i]) === false) {                    return elements;                }            }        } else {            for (key in elements) {                if (callback.call(elements[key], key, elements[key]) === false) {                    return elements;                }            }        }        return elements;    };    // 配置類型映射    $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {        class2type["[object " + name + "]"] = name.toLowerCase();    });    /**     * 定義的方法,適用於所有的Zepto對象     */    $.fn = {        slice: function() {            return $(slice.apply(this, arguments));        },        ready: function(callback) {            // 檢查document.body存在且文檔渲染完成            if (readyRE.test(document.readyState) && document.body) {                callback($);            } else {                document.addEventListener('DOMContentLoaded', function() {                    callback($);                }, false);            }        },        each: function(callback) {            emptyArray.every.call(this, function(el, idx) {                return callback.call(el, idx, el) !== false;            });            return this;        },        text: function(text) {            return 0 in arguments ?                this.each(function(idx) {                    var newText = funcArg(this, text, idx, this.textContent);                    this.textContent = (newText == null) ? '' : '' + newText;                }) :                (0 in this ? this[0].textContent : null);        },        attr: function(name, value) {            var result;            return (typeof name == 'string' && !(1 in arguments)) ?                (!this.length || this[0].nodeType !== 1 ? undefined :                    (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result                ) :                this.each(function(idx) {                    if (this.nodeType !== 1) {                        return;                    }                    if (isObject(name)) {                        for (key in name) {                            setAttribute(this, key, name[key]);                        }                    } else {                        setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)));                    }                });        },        // css屬性設定        css: function(property, value) {            if (arguments.length < 2) {                var element = this[0];                var computedStyle = getComputedStyle(element, '');                if (!element) {                    return;                }                if (typeof property == 'string') {                    return element.style[camelize(property)] || computedStyle.getPropertyValue(property);                } else if (isArray(property)) {                    var props = {};                    $.each(isArray(property) ? property : [property], function(_, prop) {                        props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop));                    });                    return props;                }            }            var css = '';            if (type(property) == 'string') {                if (!value && value !== 0) {                    this.each(function() {                        this.style.removeProperty(dasherize(property));                    });                } else {                    css = dasherize(property) + ":" + maybeAddPx(property, value);                }            } else {                for (key in property) {                    if (!property[key] && property[key] !== 0) {                        this.each(function() {                            this.style.removeProperty(dasherize(key));                         });                    } else {                        css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';';                    }                }            }            return this.each(function() {                this.style.cssText += ';' + css;            });        }    };    // 繼承    zepto.Z.prototype = $.fn;    // 在`$.zepto`命名空間匯出內部API函數    zepto.uniq = uniq;    zepto.deserializeValue = deserializeValue;    $.zepto = zepto;    return $;})();// 全域變數介面window.Zepto = Zepto;window.$ === undefined && (window.$ = Zepto);
樣本流程:當我們執行一個$("#test"),具體步驟如下:
1. 執行zepto.init2. 擷取這個元素,最後返回一個數組,然後執行 zepto.Z(dom, selector)3. 將數組化後的節點列表的__proto__執行zepto.Z.prototype,注意到zepto.Z.prototype = $.fn,$.fn下的所有方法都掛在了zepto.Z的prototype下,也就是說$("#test")已經擁有了$.fn的所有方法4. 返回數組
對應的demo頁面代碼:<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
        <meta charset="utf-8" />
        <title>Zepto源碼分析</title>
        <link rel="stylesheet" href="demo.css" type="text/css" />
    </head>
    <body>
        <div id="test">
            測試zepto源碼
            <span class="aa">22</span>
            <span class="aa">2332</span>
        </div>
        <div class="wrap">content</div>
        <script src="zepto-dev.js"></script>
        <script>
            console.log($('div'));
            console.log($('.aa'));
            console.log($('<div>這是測試內容</div>'));
            console.log($("<span />", { text: "測試測試111", id: "ceshi_111", css: { color: 'red' } }));
            Zepto(function($) {
                console.log('Ready to Zepto!');
            });
        </script>
    </body>
</html>
最後的效果如下:





linux源碼分析

linux的tcp-ip棧代碼的詳細分析

1.資料結構(msghdr,sk_buff,socket,sock,proto_ops,proto)

bsd通訊端層,操作的對象是socket,資料存放在msghdr這樣的資料結構:

建立socket需要傳遞family,type,protocol三個參數,建立socket其實就是建立一個socket執行個體,然後建立一個檔案描述符結構,並且互相建立一些關聯,即建立互相串連的指標,並且初始化這些對檔案的寫讀操作映射到socket的read,write函數上來。

同時初始化socket的操作函數(proto_ops結構),如果傳入的type參數是STREAM類型,那麼就初始化為SOCKET->ops為inet_stream_ops,如果是DGRAM類型,則SOCKET-ops為inet_dgram_ops。對於inet_stream_ops其實是一個結構體,包含了stream類型的socket操作的一些入口函數,在這些函數裡主要做的是對socket進行相關的操作,同時通過調用下面提到的sock中的相關操作完成socket到sock層的傳遞。比如在inet_stream_ops裡有個inet_release的操作,這個操作除了釋放socket的類型空間操作外,還通過調用socket串連的sock的close操作,對於stream類型來說,即tcp_close來關閉sock

釋放sock。

建立socket同時還建立sock資料空間,初始化sock,初始化過程主要做的事情是初始化三個隊列,receive_queue(接收到的資料包sk_buff鏈表隊列),send_queue(需要發送資料包的sk_buff鏈表隊列),backlog_queue(主要用於tcp中三向交握成功的那些資料包,自己猜的),根據family、type參數,初始化sock的操作,比如對於family為inet類型的,type為stream類型的,sock->proto初始化為tcp_prot.其中包括stream類型的協議sock操作對應的入口函數。

在一端對socket進行write的過程中,首先會把要write的字串緩衝區整理成msghdr的資料結構形式(參見linux核心2.4版原始碼分析大全),然後調用sock_sendmsg把msghdr的資料傳送至inet層,對於msghdr結構中資料區中的每個資料包,建立sk_buff結構,填充資料,掛至發送隊列。一層層往下層協議傳遞。一下每層協議不再對資料進行拷貝。而是對sk_buff結構進行操作。
參考資料:networking.ctocio.com.cn/tips/91/9385591.shtml
 
助:網頁原始碼分析

首先熟悉你自己使用的語言。比如C#等;
其次你要熟悉:HTML

有這兩個就可以根據該頁面的特徵來得到你想要的東西了。
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.