讀zepto核心源碼學習JS筆記(3)--zepto.init()

zepto.init()

1. 首先是第一種情況,selector為空

既然是反向分析,那我們先看看這句話的代碼;

`if (!selector) return zepto.Z()`

這里的返回值為zepto.Z();那我們繼續往上找zepto.Z()函數
java zepto.Z = function(dom, selector) { return new Z(dom, selector) }
這個函數仍然擁有一個返回值,Z函數的實例,同樣的道理,我們繼續去找Z() ;
```java
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 || ''
}
根據以上代碼可以分析出,當沒有參數時,會得到一個length:0,selector:''的對象.

QQ截圖20170608110900.png

2. 當selector為字符串的時候,又分為三種情況;

同樣的,我們先看看這句話的代碼
```java
else if (typeof selector == 'string') {
    selector = selector.trim()
}
```
  • 第一種,當selector為html片段

    if (selector[0] == '<' && fragmentRE.test(selector))
          dom = zepto.fragment(selector, RegExp.$1, context), selector = null
    
    • (1) fragmentRE.test(selector)

      這里的fragmentRE是Zepto函數在之前定義的一段正則;

      //<div>erfwef</div>  取出<div>
      fragmentRE = /^\s*<(\w+|!)[^>]*>/,
      
    • (2) zepto.fragment(selector, RegExp.$1, context)

      • RegExp.$1
        RegExp.$1為RegExp的一個屬性,指的是與正則表達式匹配的第一個 子匹配(以括號為標志)字符串;
        例子:
          var r= /^(\d{4})-(\d{1,2})-(\d{1,2})$/;
          r.exec('1985-10-15');
          s1=RegExp.$1;
          s2=RegExp.$2;
          s3=RegExp.$3;
          alert(s1+" "+s2+" "+s3)//結果為1985 10 15
      
      • zepto.fragment()函數
      //對應上面的代碼,這里第一個參數是selector,就是我們在寫代碼時的$('xxx')中的xxx,
      //name為RegExp.$1,即正則匹配的第一個()里的東西,就是標簽元素,例如 div p  h1等
      zepto.fragment = function(html, name, properties) {
            var dom, nodes, container
            // singleTagRE仍為之前定義的變量
            //singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, 匹配值如下截圖
            //如html傳入值為<p></p>,匹配singleTagRE,則創建<p></p>,并調用$('<p></p>')
            if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1))
            //如果不匹配
            if (!dom) {
              //這是一段修復代碼,將<div/>之類的不正常的代碼修復成<div></div>;
              //具體的下面再講解
              if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>")
              //如果沒有標簽名,,給他一個標簽,fragmentRE = /^\s*<(\w+|!)[^>]*>/,
              if (name === undefined) name = fragmentRE.test(html) && RegExp.$1
              //containers = {tr': document.createElement('tbody'),tbody': table, 'thead': table, 'tfoot': table,td': tableRow, 'th': tableRow,'*': document.createElement('div')},
              //如果name值不在container范圍內,則標簽名為div
              if (!(name in containers)) name = '*'
              //創建容器
              container = containers[name]
              //把html片段放入到容器中
              container.innerHTML = '' + html
              //這里調用了$.each();一會再詳細講解,這里是涉及到哪個函數我就去解析哪個函數
              //emptyArray = [], slice = emptyArray.slice,
              //所以這里的slice.call即為Array.prototype.slice.call(),能將具有length屬性的對象轉成數組;
              dom = $.each(slice.call(container.childNodes), function(){
              //刪除
                container.removeChild(this)
              })
            }
            //如果properties為對象
            if (isPlainObject(properties)) {
            //$(dom)將dom轉化成zepto對象;是為了方便調用其他方法;
              nodes = $(dom)
              $.each(properties, function(key, value) {
              //methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'],
              //如果設置的key在methodAttributes內,則直接調用zepto上的方法;
                if (methodAttributes.indexOf(key) > -1) nodes[key](value)
                else nodes.attr(key, value)
              })
            }
            //<p><span></span></p>返回[p,span]
            return dom
      }
      
      • singleTagRE
        QQ截圖20170608135118.png
      • tagExpanderRE


        QQ截圖20170608142535.png
      • fragmentR
        QQ截圖20170608173421.png
  • 第二種 當context有值

     else if (context !== undefined) return $(context).find(selector)
    

    這里涉及到一個方法find,是$.fn中的方法,之后做統一分析;

  • 第三種 沒有context;

     else dom = zepto.qsa(document, selector)
    
      zepto.qsa = function(element, selector){
          var found,
          //判斷是不是ID
          maybeID = selector[0] == '#',
          //判斷是不是css
          maybeClass = !maybeID && selector[0] == '.',
          //看是不是class和id名,如果是,將'#'或者'.'去除,然后賦值給nameOnlt;
          //否則,直接將值賦值;
          nameOnly = maybeID || maybeClass ? selector.slice(1) : selector,
          //simpleSelectorRE = /^[\w-]*$/,
          //匹配字母數字下劃線和減號的組合;
          isSimple = simpleSelectorRE.test(nameOnly)
          //如果有內置getElementById方法,并且是id名;
      return (element.getElementById && isSimple && maybeID) ?
          //則返回element.getElementByID(nameOnly)
        ( (found = element.getElementById(nameOnly)) ? [found] : [] ) :
        //反之的話,再做一次判斷
        //若element不為元素節點,document,DocumentFragment時;為空,
        (element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] :
        //否則,將節點轉換成數組;
        slice.call(
        //這里是一個三元運算符里套著另一個三元運算符;
          isSimple && !maybeID && element.getElementsByClassName ?
          //當為class,則調用element.getElementsByClassName(nameOnly) 
                maybeClass ? element.getElementsByClassName(nameOnly) :
                  //否則調用tagName;
                element.getElementsByTagName(selector) :
         //這個否則是最外層的判斷;
            element.querySelectorAll(selector)
        )
    }
    

3. 當傳入的值為函數時,則在dom加載后執行它;

else if (isFunction(selector)) return $(document).ready(selector)

4. 如果selector為Z的實例對象.則返回他自己;

else if (zepto.isZ(selector)) return selector

5. 最后,又分為5種情況;

  • 如果selector為數組;

    //
    if (isArray(selector)) dom = compact(selector)
    

    這里用到了一個compact方法;

    //這里調用了一個filter方法,是在$.fn內,以后統一分析;
    //這個函數是去除數組中的null和undefined;
    function compact(array) { return filter.call(array, function(item){ return item != null }) }
    

    所以當為數組的時候,去除數組中的null和undefined;

  • selector為對象

    else if (isObject(selector))
        dom = [selector], selector = null
    

    如果selector為對象,將對象變為一個數組;

  • selector為html片段;則將其轉換成dom

    else if (fragmentRE.test(selector))
        dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
    
  • 有context的時候

    else if (context !== undefined) return $(context).find(selector)
    
  • 沒有context

    else dom = zepto.qsa(document, selector)
    
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容