jQuery的链式操作原理简介

时隔这么几个月,再次写一下jQuery中的一些东西,这里想要说的是jQuery中的链式操作。它让代码变得更有层次更简洁。

概况

这里就先说一下jQuery中链式操作的基础,其根本思想就是在利用构造函数在做这个处理,那么如果想要更好的理解下面的内容,最好要对构造函数有一些基本的认识才行,如果您对构造函数以及构造函数的实例化的认识不多,那么请先看之前的一篇文章,可以让您对构造函数有一个基本的认识,并拥有足够的知识让您继续看下面的内容,了解到jQuery中的链式操作的实现方法。

自定义创建对象的几种方法对象继承的方法小结原型链断链的原因

简化的实例

我个人在想说明一些代码的实现思想时,总会以最简单的实例来说明某个问题,现在依然是使用最简单的一个实例来说明,下面的代码是取自jQuery源码中的实现:


var rootjQuery = null,
    //rootjQuery只是用于jQuery函数中的第三个参数,预定义的
    //在这里,是没有意义的。
	
    jQuery = function( selector, context ) {
	//jQuery方法,也就是我们常用的选择器$符。
	//在jQuery中,我们每次使用$或者jQuery进行元素选择时
	//都会调用该方法,返回一个包含目标元素的类数组
	return new jQuery.fn.init( selector, context, rootjQuery );
		
	//当调用jQuery时,则对jQuery.fn.init函数进行实例化
	//并把该实例当做返回值。
	//返回的实例中,包含init函数的实例属性和方法,
	//以及原型链中的属性和方法。
    };

//jQuery.fn = jQuery.prototype
//这里,jQuery中的代码是上面注释掉的这个,
//但是对于我们这里要说的问题,可以只使用下面的方法即可
jQuery.fn = {
    //这里给jQuery定义一个静态对象fn(其实应该成为静态属性),
    //并且这个方法内部包含init和toArray方法
    init: function( selector, context, rootjQuery ) {
	console.log("jQuery.init");
    },

    toArray: function() {
	console.log("jquery.toArray");
    }
};

jQuery.fn.init.prototype = jQuery.fn;
//这里就是链式操作的开始
//前面也说了,当调用jQuery方法时
//返回了jQuery.fn.init函数的一个实例
//那么在构造函数的实例中,就可以访问构造函数中prototype中的属性和方法
//所以,当我们每次调用jQuery()进行操作时,返回的一个实例中,都可以调用jQuery.fn中所包含的所有的方法。
//所以,我们就可以这样的调用:jQuery().init();jQuery().toArray();

jQuery().init();
//jQuery.init
//jQuery.init
jQuery().toArray();
//jQuery.init
//jQuery.toArray


按照上面的写法,所谓的链式操作也就在这里借宿了,很明显,这并不是jQuery当前实现的样子,那么如何能多次进行链式操作呢。

这里就需要懂得一点,看下面这种写法:


var name = "zhangzhang",
    obj = {
        name:"zhang",
	getName:function(){
	    return this.name;
	}
    };

console.log(obj.getName());


对于上述代码中的this指代的是哪个对象呢?

懂得了上述中this的指代,那么我们之前想要解决的问题,也就很简单了。

只需要对需要继续支持链式操作的方法,有一个返回值即可。

所以代码修改为如下样式:


var rootjQuery = null,
    jQuery = function( selector, context ) {
	return new jQuery.fn.init( selector, context, rootjQuery );
    };

jQuery.fn = jQuery.prototype = {
    init: function( selector, context, rootjQuery ) {
	console.log("jQuery.init");
	return this;
    },

    toArray: function() {
	console.log("jquery.toArray");
	return this;
    }
};

jQuery.fn.init.prototype = jQuery.fn;

jQuery().init().init().toArray().init().toArray();
//控制台打印的结果如下:
//jQuery.init
//jQuery.init
//jQuery.init
//jquery.toArray
//jQuery.init
//jquery.toArray

 

到这里,关于链式操作的原理代码,也就介绍了,我都是按照自己的理解,进行的简单的说明,如有问题,请指点。

jQuery的第二个参数

不知道你有没有注意到一点,就是jQuery方法是可以传入两个参数的,那第二个参数是如何使用的呢,下面就看下如何使用第二个参数:

先看个例子,html布局部分如下:


<div id ="test">
    <div class = "item">test1</div>
    <div class = "item">test2</div>
    <div class = "item">test3</div>
</div>


那么我们想要查找id=test元素下的所有的class=item的元素,通常情况下,我们会使用的方法是:jQuery("#test .item");

但是,我们有时候,我们也需要对id=test的元素进行一些处理,所以,我们首先要做的就是要先把id=test的元素取出来,并且还需要id=test元素下class=item的元素,通常我们有以下多种方法:


var test = jQuery("#test"),
    allDiv = jQuery("#test .item");
console.log(test);
console.log(allDiv);
//该方法的不好之处在于当取allDiv时,又再次查找了id=test的元素
//这样肯定效率相对较低
//试想要去一个小区找人,要先找到在哪栋楼,然后在该楼再找到在哪个房间。
//这里的id=test就是那栋楼,如果我们已经知道了在那栋楼,
//还依然从整个小区的规模去找,那么效率肯定就会相对较低了
//所以,才有下面的方法

allDiv = test.children(".item");
console.log(allDiv);
//该方法,就是,在寻找class=item的时候,是以id=test的元素开始的
//就想比于,找人是从一栋楼开始的,相对于前一种写法,有更高的效率
//但是有个缺点仍然是,它只能查找直接子元素。
//所以就有了下一种方法


allDiv = test.find(".item");
console.log(allDiv);
//这个本来是我认为最常用的方法了吧,当然,是使用find方法还是使用children方法,主要还是看,你要查找的范围是在一个怎么样的范围。

//现在看了jQuery实现的方法,那么就又看到了另外一个寻找子元素的方法了
//注意到了没,jQuery函数是可以接受第二个参数的,那么第二个参数是代表了什么意思呢?
//就是范围的意思,在这个范围的基础上,查找第一个参数的所要匹配的元素
//所以,这里可以这么来查找
allDiv = jQuery(".item",test);
console.log(allDiv);

//由结果可以看出,它是完成了和find相同的功能,
//当然,这里的第二个参数也可以直接以字符串的形式书写。
//写法如下:
allDiv = jQuery(".item","#test");
console.log(allDiv);

//获取到的结果,和前面的一样,
//只是如果是这样的写法,
//我们当然还是喜欢最简单的一个参数的组合写法了,
//所以这个我觉得是没有太大的意义的
//而这里因为这种方法的功能和find方法,完成的是相同的功能,
//而我这里也还不能验证,哪种方法,性能更优
//当然,如果是写法的话,find方法更符合jQuery的主流写作方法
//所以,这里只是想说明一下,jQuery的选择器方法,
//其实是支持第二个参数的


注:2014.9.20

jQuery.fn.init函数的内部,当jQuery(selector,context)时,如果有第二个参数context的输入,那么会有这么一个逻辑,this.constructor( context ).find( selector );也就是会所,如果有第二个参数的话,因为在jQuery.fn对象中,有这么一个属性,jQuery.fn.constructor= jQuery,所以,上式就可以变成jQuery(context).find(selector)了,所以,这样看来,第二个参数其实还不如我们直接以find方法查找,更具有优势的。

所以,这个算是为了什么,才给留的一个第二个参数呢?

扩展

既然说到这里,那么也就顺便说下jQuery.extendjQuery.fn.extend对jQuery的扩展,在使用上的不同,也就很明显了

由上一小节中的简单的代码中,可以看出jQuery是一个函数,那么使用jQuery.extend进行扩展则是把新的方法,扩展到jQuery的静态属性和方法上,在使用时,只能通过jQuery.name的方法进行调用,新方法的层级是和上一小节中的fn方法同级。

jQuery.fn.extend方法,则是把新的方法或者属性扩展到了jQuery.fn对象上,而该对象上的对象,是可以进行链式操作的。并且通过该方法添加的属性或者方法,会立刻在jQuery的所有对象中得到体现(这句话说得不清,看下面的例子)。

在上一小节代码的基础上,添加如下的一段代码:


var a = jQuery().init();
//jQuery.init
//jQuery.init

jQuery.fn.toObject = function(){
    console.log("jquery.toObject");
    return this;
}

//新添加的方法,可以在a对象中使用
//这是由原型链的共享特性决定的
a.toObject().toArray();
//jquery.toObject
//jquery.toArray


如果对上述内容有疑问,请提出,或者请参考在第一小节中链接的三篇文章。

本文地址:http://www.zhangyunling.com/?p=207

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>