jQuery源码分析之jQuery.eq()和jQuery.get()方法比较

首先来一段测试代码:

JS部分:

//这里要记住了:通过源码分析,如果length不在有效范围之内那么传入pushStack
//的参数是[]也就是空对象,所以返回空的jQuery对象!
//打印:function(a,b){return new m.fn.init(a,b)}
//$("div").constructor.length表示形参的个数
alert("选择器构造函数:"+$("div").constructor);
//打印[object HTMLDocument]
alert("选择器上下文:"+$("child").context);
//下面打印true,说明选择器返回对象的contructor是jQuery对象
alert($("div").constructor() instanceof jQuery);
//merge函数调用之前不是jQuery对象,这是和get或者下标访问一样的结果只是DOM
alert("merge函数调用之前->"+([$("div")[0]] instanceof jQuery))
//返回false
//merge函数通过把DOM对象的属性逐个封装到jQuery对象上,构建jQuery对象返回
var ret = jQuery.merge( $("div").constructor(), [$("div")[0]]);
alert("merge函数调用后->"+(ret instanceof jQuery));
//打印true,merge后已经是jQuery对象了
//这里为undefined,因为我是直接merge,没有调用pushStack,所以没有封装到prevObject。调用eq就相当于调用pushStack方法了!
alert("新jQuery返回旧的jQuery"+(ret.prevObject));
//也就是如果需要访问原来的选择器结果对象,如$("p")那么应该用prevObject
//下面返回true
alert("调用eq后就会有prevObject->"+($("div").eq(0).prevObject instanceof jQuery));

 
  

测试代码2:

//下面返回“test”,也就是说调用eq后如果要获取到上一次的选择结果,就可以用prevObject。因为调用eq的时候通过prevObject保存了上一次的this,
//也就是选择的jQuery对象。$("div").eq(0).prevObject相当于$("div")
alert($("div").eq(0).prevObject.eq(0).attr("id"));

测试代码3:

alert($("p").eq(1).constructor);
 // 打印:function(a,b){return new m.fn.init(a,b)}

eq源码分析:

 eq: function( i ) {
var len = this.length,
j = +i + ( i < 0 ? len : 0 );//可以传入数字字符串!因为+就是将他变成数字!
//传入的参数是[this[j]]=[DOM元素]=[$("p")[0]]
return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
}

因为eq方法调用了pushStack所以他的返回值类型是jQuery类型;同时在pushStack中调用了jQuery.merge里面把所有的这里的DOM数组中的对象封装到一个空的jQuery对象上面并且返回!

pushStack源码:关于context详见codeplayer

 pushStack: function( elems ) {
// Build a new jQuery matched element set
//创建新的jQuery对象集合
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
//用prevObject保存选择器的结果,也就是上面的eq函数的this对象
ret.prevObject = this;
 //保存上下文,默认是document
ret.context = this.context
//eq方法归根到底还是通过下标访问来完成的,通过把访问的下标的DOM对象逐个封装到空的JQuery对象中完成新的jQuery对象的构建!
// Return the newly-formed element set
return ret;
}

get方法源码:

get: function( num ) {
return num != null ?
// Return just the one element from the set
( num < 0 ? this[ num + this.length ] : this[ num ] ) :
//如果没有参数,如$("ul li").get()调用,那么this就是指$("ul li")的选择结果是jQuery对象,通过slice后返回的对象是Array
// Return all the elements in a clean array
slice.call( this );
}

我们看到如果调用get方法时候没有传入参数,那么调用了[].slice.call方法,从而把类数组的jQuery对象转化为了Array类型了!

测试例子:

//返回false,get方法返回的是DOM对象
alert($("ul li").get() instanceof jQuery);
alert($("ul li").get());
//返回[object HTMLLiElement],[object HTMLLiElement],[object HTMLLiElement]
//没有参数返回是数组,结果为true
alert($("ul li").get() instanceof Array);
//get没有参数的时候,this是jQuery对象,也就是选择器的结果如$("ul li")
//通过slice就可以把jQuery对象$("ul li")转化为JS对象.下面返回都是true
alert(Array.prototype.slice.call($("ul li")) instanceof Array);
alert(Array.prototype.slice.call($("#me")) instanceof Array);
总结:

(1)通过源码分析,传入到eq函数的length不在有效范围之内那么传入pushStack的参数是[]也就是空对象! 这时候返回的jQuery对象不包含任何DOM对象!
(2)var ret = jQuery.merge( $("div").constructor(), [$("div")[0]]); 可以把后面数组中的对象全部封装到前面的空的jQuery对象上面,构成一个新的jQuery对象!

(3)对于get方法我们通过是下标来访问的,如果没有传入参数那么通过slice返回整个调用对象的DOM集合,否则返回特定的项。如果是负数,那么eq和get是一样的,都是通过加上调用对象的长度!

你可能感兴趣的:(jQuery源码)