Heim >Web-Frontend >js-Tutorial >jQuery的运行机制和设计理念分析_jquery

jQuery的运行机制和设计理念分析_jquery

WBOY
WBOYOriginal
2016-05-16 18:08:401100Durchsuche

其短小精悍,使用简单方便,性能高效,能极大地提高开发效率,是开发Web应用的最佳的辅助工具之一。因此大部分开发者在抛弃Prototype而选择jQuery来进行Web开发。

一些开发人员在使用jQuery时,由于仅仅只知道jQuery文档中的使用方法,不明白jQuery的运行原理,时常会碰到许多的问题。这些问题大部分是使用不当而产生,极少数是jQuery的Bug。如果不明白其运行机理和核心源码,我们也很难写出基于jQuery类库的高性能的程序出来。

在调试基于jQuery的程序时,我们大部分时间都要跟踪进入jQuery对象分析其运行的状态,但是jQuery代码不像Ext,YUI那样中规中举,它的代码有点晦涩,难懂。也就说如果想用好jQuery,一定要清楚其源码。

jQuery的设计理念

使用jQuery之前,我们都会问jQuery是什么?jQuery是一个类库,和prototype,mootools等类库一样,为Web的 JavaScript开发提供辅助功能。那为什么要选用jQuery呢?在jQuery出现之前,Prototype,YUI都是很成熟的Js的框架,而且是各有各的特点。为什么要抛弃它们,而使用后起之秀的jQuery,它有什么优秀的特性吸引开发人员呢?

回答这个问题,我们得明白jQuery的设计理念。回忆或想象一下,我们在Web开发中是如何使用JavaScript?绝大多数时间都是采用 getElementById在Dom文档中找到DOM元素,然后取值或设定值,采用innerHTML取其内容或设定其内容,或进行事件的监听(如 click),在控制样式方面,我们会进行height,width,display等的改变,达到视觉上的效果,对于Ajax方面,也是取到数据在页面的某元素里面去添充内容。

综之,我们就是在对DOM元素在进行操作。这个元素可能是一个或是多个。这个元素可能是Document,Window或DOM元素。这样我们的任务就是二大部分,一是找DOM元素,二是对DOM元素进行操作。

对于用得熟练一点,不管是采用如getElementById这样的直接查找方式还是采用如Element.lastChild这类的间接查找方式不是很难的,对于DOM元素,DOM的操作方面也是很丰富,也不是很难使用?那么要类库做什么用呢?最难的一个问题就是浏览器的兼容的问题。所有的 JavaScript框架都要解决这一个问题,同时简化JavaScript的本身自带的操作。

Prototype可以说是开创了Js类库的先河,给我们耳目一新的感觉。它解决大部分的浏览器的兼容的问题。同时简化了原始函数名长难于记忆的经常书写出的错的问题(采用$(xx)代替getElementById),提供了Ajax的访问方式,扩展了 Array,Object,Function,Event等JavaScript原生对象。

但是这些还是不能满足开发的需要,比如在DOM树中寻找DOM元素,仅仅只能是通过元素的ID,但是我们想要更方便的查找方法,同时还希望能有一个统一的入口,不要太泛,学习曲线过高或难于使用。

jQuery就是从这里出发,把所有一切都统一在jQuery对象中。使用jQuery就是使用jQuery对象。其实jQuery开创性的工作就是如其名一样:query。它强大的查找功能令所有的框架都黯然失色。jQuery实质就是一个查询器。在查询器的基础还提供对查找到的元素进行操作的功能。这样说来jQuery就是查询和操作的统一。查询是入口,操作是结果。

jQuery在实现上也可以分成两大部分,一部分是jQuery的静态方法,也可以称作实用方法或工具方法,通过jQuery.xxx()的 jQuery命名空间直接引用。第二部分是jQuery的实例方法,通过jQuery(xx)或$(xx)来生成jQuery实例,然后通过这个实例来引用的方法。这部分的方法大多数是从采用静态方法代理来完成功能。真正的功能性的操作都在jQuery的静态方法中实现。这些功能细分起来,可以分成以下几个部分:

1、Selector,查找元素。这个查找不但包含基于CSS1~CSS3的CSS Selector功能,还包含其对直接查找或间接查找而扩展的一些功能。

2、Dom元素的属性操作。Dom元素可以看作html的标签,对于属性的操作就是对于标签的属性进行操作。这个属性操作包含增加,修改,删除,取值等。

3、Dom元素的CSS样式的操作。CSS是控制页面的显示的效果。对CSS的操作那就得包含高度,宽度,display等这些常用的CSS的功能。

4、Ajax的操作。Ajax的功能就是异步从服务器取数据然后进行相关操作。

5、Event的操作。对Event的兼容做了统一的处理。

6、动画(Fx)的操作。可以看作是CSS样式上的扩展。

jQuery对象的构建

生成或构建一个jQuery对象其实就是构建并运行一个查询器(selector)。既然是查询,肯定会查找的结果(DOM元素),之后才会有对这些结果进行操作。那么这些查找的结果存放在哪里呢?最好的地方当然是这个jQuery对象内面。查找的结果可能是一个元素,也有可以是多个元素如 (NodeSet的集合的形式)。也就是说jQuery对象内面有一个集合。这个集合存放查找到DOM元素。

但是上一小节所提到jQuery对象是所有操作的统一入口,那么它的构建就不能只局限于从DOM文档中查找到DOM元素,还有可能是从别的集合中转移过来的Dom元素,还有可能是从HTML的字符串生成的DOM元素。

在jQuery文档中提供了四种方式:jQuery(expression, [context]),jQuery(html),jQuery(elements),jQuery(callback)四种构寻jQuery对象的方式。其中jQuery可以用$代替。这四种是经常用到。其实jQuery的参数可以是任何的元素,都能构成jQuery对象。

举几个例子:

1、$($("P"))可以看出其参数可以是jQuery对象或ArrayLike的集合。

2、$()是$(document)的简写。

3、$(3)会把3放到jQuery对象中集合中。

对于如$(3)这样的其中元素(如ArrayLike集合的元素)不是DOM元素,最好不要构建jQuery对象,jQuery对象的方法都是针对于DOM对象的。不是很清楚其使用的话,很有可能会导致错误。上面讲了这么多,还是很难明白其原理的,现在从源码的角度细细分析:

通过jQuery(xxx)的调用实现没有生成对象,它的this是指向Window对象的。那么jQuery的那些实例方法是怎样继承过来的呢?看一下:

var jQuery = window.jQuery = window.$ = function(selector, context)
{ return new jQuery.fn.init(selector, context);
};
这是jQuery的总的入口,jQuery对象实际上不是通过new jQuery()而继承其prototype的中的方法。jQuery对象实际是jQuery.fn.init函数生成的对象。在里我们可以看出对于 jQuery.prototype添加一些函数集的对象的意义不大。因为我们new jQuery()是可以的,但是生成的jQuery对象在return时会被抛弃。所以最好不要用new jQuery()来构建jQuery对象。jQuery对象其实就是new jQuery.fn.init。那么jQuery.fn.init.prototype上就是挂着jQuery对象的操作方法。如

jQueryjQuery.fn.init.prototype = jQuery.fn;
有时间可能会担心在589行就实现了把jQuery.fn中的函数放到jQuery.fn.init.prototype上去,那么之后的通过 jQuery.fn.extend的方法怎么办呢?这里实际是对jQuery.fn的引用。在扩展jQuery的时候,只要把相关的函数extend到 jQuery.fn就可以了。现在我们看一下jQuery.fn.init是怎么完成工作的:

复制代码 代码如下:

init : function(selector, context) {
selectorselector = selector || document;// 确定selector存在

// 第一种情况 Handle $(DOMElement)单个Dom 元素,忽略上下文

if (selector.nodeType) {
this[0] = selector;
this.length = 1;
return this;
}

if (typeof selector == "string") {//selector为string
var match = quickExpr.exec(selector);
if (match && (match[1] || !context)) {
if (match[1])// 第二种情况处理$(html) -> $(array)
selector = jQuery.clean([match[1]], context);
else {// 第三种情况:HANDLE: $("#id")//处理$("#id")
var elem = document.getElementById(match[3]);
if (elem) {
// IE会返回name=id的元素 ,如果是这样,就document.find(s)
if (elem.id != match[3])
return jQuery().find(selector);
// 构建一个新的jQuery(elem)
return jQuery(elem);
}
selector = [];
}
} else

// 第四种情况:处理$(expr, [context])==$(content).find(expr)
return jQuery(context).find(selector);
} else if (jQuery.isFunction(selector)) // 第五种情况:处理$(function)七Shortcut for document ready
return jQuery(document)[jQuery.fn.ready ? "ready" : "load"](selector);

// 第六种情况:处理$(elements)
return this.setArray(jQuery.makeArray(selector));
}
Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn