jQuery Utilities 分类下的函数(或属性)的实现方式分析
jQuery Utilities 分类下的函数(或属性)的实现方式分析
本文将介绍jQuery Utilities 分类下的函数(或属性)的实现方式。
首先,可以先从 jQuery 官方 API 中找到 Utilities 分类的介绍:
http://api.jquery.com/category/utilities/
其中,不进行分析的函数(或属性)包括:
jQuery.boxMode:已经不推荐使用,可以用 jQUery.support.boxModel 代替
queue相关函数:与动画相关,并且也属于 “Custom” 分类,等分析 “Custom” 分类下的函数时再一并分析
已经分析过的函数(或属性):
jQuery.browser :http://xxing22657-yahoo-com-cn.iteye.com/blog/1035780
jQuery.data() :http://xxing22657-yahoo-com-cn.iteye.com/blog/1042440
jQuery.extend() :http://xxing22657-yahoo-com-cn.iteye.com/blog/1025297
jQuery.unique() :http://xxing22657-yahoo-com-cn.iteye.com/blog/1038480
jQuery.support :http://xxing22657-yahoo-com-cn.iteye.com/blog/1044984
另外,jQuery.isArray(), jQuery.isPlainOject(), jQuery.isWindow(), jQUery.type() 在分析 jQuery.extend() 时已经一并分析。
这里更给出的实现都是简化的版本,没有考虑性能优化、异常处理和某些特殊情况。实际上,jQuery的完整实现完全可以自己在未压缩版的源代码(这里分析的版本是 jQuery 1.6)中 search,因为这里主要讲解实现思路,作为引导和参考,所以下面的分析中将忽略一些次要因素,以避免冲淡主题。
jQuery.globalEval()
通常情况下使用 eval,this 所指向的都是当前对象;有的时候我们希望 this 指向全局对象( window ),就可以使用 jQuery.globalEval() 了。这在动态加载外部 JavaScript 文件并执行时十分有用。
功能测试代码如下:
可以看到,通常情况下调用附加在对象上的函数,并在函数中使用 eval() 时, this 并不指向 window;但如果使用 globalEval() ,那么 this 就会指向 window 。
简单的实现方式如下:
显示结果如下:
显示结果如下:
parseJSON() 只需要直接创建一个 Function ,并将内容设置为 "return " + data 就可以了。这类似于 eval 。因为 JSON 本身就是 JavaScript 的对象(或数组)的格式,因此转换起来异常简单。同样地,jQuery 的源代码中优先检查了 window.JSON.parse ,如果存在则使用浏览器内置的解析器。虽然可能在性能上略有提升,但也可能导致不同浏览器中的解析行为有所不同(通常我会把这个检查注释掉)。
parseXML() 需要分两种情况,大多数浏览器都可以使用 DOMParser 进行解析,但 IE 中需要使用 ActiveXObject。jQuery 源代码中还有一些抛出 error 的处理。
jQuery.trim()
jQuery.trim() 函数用于去除字符串中的空白字符。
功能测试代码如下:
我们可以用正则表达式实现这个功能:
实现方式如下:
实现方式如下:
简单实现如下:
parseXML() 的实现请参考之前的分析。
isXMLDoc() 的实现方式为检查元素的 documentElement 是否存在,存在且不为 HTML ,则表示这是一个 XML 文档。
jQuery.contains()
检查一个 DOM Element 是否包含了另一个 DOM Element。
功能测试代码如下:
简单实现如下:
简单实现如下:
简单实现如下:
简单实现如下:
首先检查输入参数是否为“单个”对象,是的话就 push 到数组中,不是的话就 merge 到数组中。
class2type, type(obj), isWindow(obj) 的实现请参考: http://xxing22657-yahoo-com-cn.iteye.com/blog/1025297
meger(a, b) 的实现请参考上一小节。
jQuery.each()
该函数提供一种遍历数组和对象的函数,支持传入一个回调函数,在遍历过程中执行。
功能测试代码如下:
简单实现如下:
简单实现如下:
可以看出,如果返回值为 undefined 或 null 时,表示该元素不会被保留;因此,我们完全可以用 jQuery.map() 代替 jQuery.grep() 。
简单实现如下:
实现方式如下:
移除通过对象附加的数据:
移除附加到 DOM Element 上的数据:
实现方式如下:noop: function() {}
以上就是就是我对 jQuery Utilities 分类下的函数的实现方式的分析了。
题外话
最近一直在看 jQuery 的源代码,jQuery 源码算是一个学习JavaScript编程模式的经典范例吧。之所以决定花时间钻研JavaScript,一个重要的原因是最近 server-side JavaScript 和 一些 “JavaScript Friendly” 的 NoSQL 数据库似乎在慢慢兴起。仔细想想, JavaScript 也算是一门各大厂商都在努力改善的语言了(浏览器之争推动了 JavaScript 性能的提升),并且 JavaScript 的一些语言特性也比较有吸引力。
分析 jQuery 源码的思路,是先从 API 入手,“自底向上”地进行分析,先把基础函数了解清楚,再去看“高阶函数”的实现。具体分析某个函数(或属性)时,先测试这个函数(或属性)的功能,再想办法自己实现一遍,然后与jQuery的实现进行比较。
我简单地搜索了一下,这边分析过jQuery源代码的朋友也不少,能否分享一下经验? 1 楼 denger 2011-05-16 不错,分析的很详实。 2 楼 裴小星 2011-05-19 突然想到,区分数组(或“类数组”)和对象还是有必要的。
$('body')方式产生的对象就是一个“类数组”,有length,有下标等,
但又有其他属性(及函数),
直接用 for (i in $('body'))遍历是有问题的,
还是应该检查 length 属性,用 for (i = 0; i < xxx.length; ++i) 遍历