上篇已经讲解了zepto.init()的几种情况,这篇就继续记录这几种情况下的具体分析.
1. 首先是第一种情况,selector为空
既然是反向分析,那我们先看看这句话的代码;
if (!selector) return zepto.Z()
这里的返回值为zepto.Z();
那我们继续往上找zepto.Z()函数
zepto.Z = function(dom, selector) {return new Z(dom, selector)
}
这个函数仍然拥有一个返回值,Z函数的实例,同样的道理,我们继续去找Z()
;
function Z(dom, selector) {var i, len = dom ? dom.length : 0for (i = 0; i < len; i++) this[i] = dom[i]this.length = lenthis.selector = selector || ''
}
根据以上代码可以分析出,当没有参数时,会得到一个length:0,selector:''
的对象.
2. 当selector为字符串的时候,又分为三种情况;
同样的,我们先看看这句话的代码
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函数在之前定义的一段正则;
```java
//<div>erfwef</div> 取出<div>
fragmentRE = /^\s*<(\w+|!)[^>]*>/,
```
2 zepto.fragment(selector, RegExp.$1, context)
* RegExp.$1
RegExp.$1为RegExp的一个属性,指的是与正则表达式匹配的第一个 子匹配(以括号为标志)字符串;
例子:java 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()
函数
```java
//对应上面的代码,这里第一个参数是selector,就是我们在写代码时的$('xxx')中的xxx,name为RegExp.$1,即正则匹配的第一个()里的东西,就是标签元素,例如 div p h1等,properties为执行环境.
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范围内,则标签名为divif (!(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)})}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
}
```
以上代码出现了singleTagRE
- singleTagRE
- tagExpanderRE
- fragmentRE
- 第二种 当context有值
else if (context !== undefined) return $(context).find(selector)
这里涉及到一个方法find,是$.fn中的方法,之后做统一分析;
- 第三种 selector为普通选择器
else dom = zepto.qsa(document, selector)
zepto.qsa = function(element, selector){var found,//判断是不是IDmaybeID = selector[0] == '#',//判断是不是cssmaybeClass = !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为数组;
java // if (isArray(selector)) dom = compact(selector)
这里用到了一个compact方法;java //这里调用了一个filter方法,是在$.fn内,以后统一分析; //这个函数是去除数组中的null和undefined; function compact(array) { return filter.call(array, function(item){ return item != null }) }
所以当为数组的时候,去除数组中的null和undefined;- selector为对象
java else if (isObject(selector)) dom = [selector], selector = null
如果selector为对象,将对象变为一个数组; - selector为html片段;则将其转换成dom
java 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
java else dom = zepto.qsa(document, selector)