最近在看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.matchesSelectorif (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/663245function isPlainObject(obj) {return isObject(obj) && !isWindow(obj) && obj.__proto__ == Object.prototype}function isArray(value) {return value instanceof Array}//类数组,比如nodeList,这个只是做最简单的判断,如果给一个对象定义一个值为数据的length属性,它同样会返回truefunction likeArray(obj) {return typeof obj.length == 'number'}
3、数组操作
//清除给定的参数中的null或undefined,注意0==null,'' == null为false
//这个很赞,用filterfunction 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() //转成小写}