zepto学习之路--源代码提取
最近在看zepto的源代码,把一些有用的函数摘出来,看看zepto是怎么实现的,自己做的时候也可以用。说实话,zepto的实现有一些看起来还是很晦涩的,可能是自己的水平不够,看不透作者的真正的意图。
1、zepto的正则总结:
//HTML代码片断的正则 fragmentRE = /^\s*<(\w+|!)[^>]*>/ //匹配非单独一个闭合标签的标签,类似将<div></div>写成了<div/> tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig //根节点 rootNodeRE = /^(?:body|html)$/i //class选择器的正则 classSelectorRE = /^\.([\w-]+)$/, //id选择器的正则 idSelectorRE = /^#([\w-]*)$/, //DOM标签正则 tagSelectorRE = /^[\w-]+$/,
2、zepto工具函数总结(我的意思只是我感觉比较有用的哈):
//判断一个元素是否匹配给定的选择器 //这里作者的实现我觉得有点小问题,其思想是在其父元素中按照selecor找出匹配的元素再indexOf判断是否存在,但是,如果selector是这样的呢“body div .a”,在其父元素中能匹配到body吗?我觉得还不如直接在document下匹配,欢迎拍砖。可能是我笨吧,或者zepto的qsa函数比较高级。 zepto.matches = function(element, selector) { if (!element || element.nodeType !== 1) return false //引用浏览器提供的MatchesSelector方法 var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector || element.oMatchesSelector || element.matchesSelector if (matchesSelector) return matchesSelector.call(element, selector); //如果浏览器不支持MatchesSelector方法,则将节点放入一个临时div节点, //再通过selector来查找这个div下的节点集,再判断给定的element是否在节点集中,如果在,则返回一个非零(即非false)的数字 // fall back to performing a selector: var match, parent = element.parentNode,temp = !parent //当element没有父节点,那么将其插入到一个临时的div里面 if (temp)(parent = tempParent).appendChild(element) //将parent作为上下文,来查找selector的匹配结果,并获取element在结果集的索引,不存在时为-1,再通过~-1转成0,存在时返回一个非零的值 match = ~zepto.qsa(parent, selector).indexOf(element) //将插入的节点删掉 temp && tempParent.removeChild(element) return match }
接下来就有个大问题了,是zepto的类型判断部分,求解答:
//问题在这里,下面的type函数中,很明显有问题啊,class2type[toString.call(obj)]我感觉不对啊,我感觉应该是toString.call(obj).slice(8,-1);待我去知乎上问下,再分享给大家。
//好吧,我承认自己太急躁了原来还有下面这么一段,
$.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { | |
class2type[ "[object " + name + "]" ] = name.toLowerCase() | |
}) |
var class2type={},toString=class2type.toString;
function type(obj) { //obj为null或者undefined时,直接返回'null'或'undefined' 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" } //对于通过字面量定义的对象和new Object的对象返回true,new Object时传参数的返回false //可参考http://snandy.iteye.com/blog/663245 function isPlainObject(obj) { return isObject(obj) && !isWindow(obj) && obj.__proto__ == Object.prototype } function isArray(value) { return value instanceof Array } //类数组,比如nodeList,这个只是做最简单的判断,如果给一个对象定义一个值为数据的length属性,它同样会返回true function likeArray(obj) { return typeof obj.length == 'number' }
3、数组操作
//清除给定的参数中的null或undefined,注意0==null,'' == null为false //这个很赞,用filter function compact(array) { return filter.call(array, function(item) { return item != null }) } //类似得到一个数组的副本,拷贝数组a就return a.concat([]);很赞 function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array }
//数组去重,如果该条数据在数组中的位置与循环的索引值不相同,则说明数组中有与其相同的值
//数组去重的方法有很多,但作者的这个方法真心赞,让我折服了,即短又高效!
uniq = function(array) {
return filter.call(array, function(item, idx) {
return array.indexOf(item) == idx
})
}
4、字符串操作
//将字符串转成驼峰式的格式 camelize = function(str) { return str.replace(/-+(.)?/g, function(match, chr) { return chr ? chr.toUpperCase() : '' }) } //将字符串格式化成-拼接的形式,一般用在样式属性上,比如border-width //这个写的太赞了,真的是每一句都很赞,由衷的佩服。 function dasherize(str) { return str.replace(/::/g, '/') //将::替换成/ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') //在大小写字符之间插入_,大写在前,比如AAAbb,得到AA_Abb .replace(/([a-z\d])([A-Z])/g, '$1_$2') //在大小写字符之间插入_,小写或数字在前,比如bbbAaa,得到bbb_Aaa .replace(/_/g, '-') //将_替换成- .toLowerCase() //转成小写 }