一、jQuery函数
先回顾一下我们常用的jQuery格式,例如我们需要设置一个div的css样式,那么会写成如下的格式:$(“#btn”).css()
,就有点类似于一个对象调用自己的方法,$(“#btn”)
是一个执行函数,在文档的61行:
我们可以发现在63行,函数返回的是一个通过new创建的对象,这也是jQuery的巧妙之处,不通过new构造函来创建对象。这里具体分析一下。
一般如果我们听过构造函数来创建的话,会写成如下格式:
function jquery(){} //创建构造函数
jquery.prototype.init = function() {}; // 原型初始化方法
jquery.prototype.css = function(){}; // 原型css方法
var JQ = new jquery(); //创建实例
JQ.init(); //调用初始化方法
JQ.css(); //调用css方法
这样,我们就需要通过new来创建新的对象,如果我们将new操作写在构造函数就可以达到类似于文档中61到63行的作用。那么返回的对象到底是什么?
return new jQuery.fn.init( selector, context, rootjQuery );
这里返回的是一个初始化构造的对象,那么这个对象是怎么与jQuery对象联系上的呢?在文档的283行能找到关于jQuery.fn.init()
设置:
而关于jQuery.fn
的设置在96行能找到:
上面两行指令可以等效为如下:
jquery.prototype.init.prototype = jquery.prototype;
将一个对象的原型赋值给另外一个对象的原型,也就是原型的引用。这样的话,改变jquery的原型也就等于改变了jquery.prototype.init的原型。也就是说在jQuery原型下定义方法,都可以在new出来的jQuery.fn.init()
下使用。
二、jQuery对象的属性和方法
96~280行给jQuery对象增加一些原型属性和方法,其属性和方法简化如下:
jQuery.fn = jQuery.prototype = {
jquery: 版本号;
constructor: 指定构造函数;
init(): 初始化以及管理参数,也就是选择器的处理;
selector: 存储选择字符串;
length: this对象的长度;
toArray(): 转数组;
get(): 转原生集合;
pushStack(): JQ对象的入栈;
each(): 遍历集合;
ready(): DOM加载的接口;
slice(): 集合的截取;
first(): 集合的第一项;
last(): 集合的最后一项;
eq(): 集合的指定项;
map(): 返回新的集合;
end(): 返回集合前一个状态;
push(): 内部使用;
sort(): 内部使用;
splice(): 内部使用;
};
下面对jQuery对象中的部分属性和方法详细介绍一下:
1、constructor: 指定构造函数
构造函数属于对象的一个属性,对象创建时就自带一个constructor属性,该属性指向对象对应的构造函数。先看两种情况下constructor的值:
第一种情况:
function aaa(){}
var Oa = new aaa();
console.log(Oa.constructor); // function aaa(){}
第二种情况,往构造函数上添加原型属性和方法:
function aaa(){}
aaa.prototype = {
name : "sean",
age : 21
};
var Oa = new aaa();
console.log(Oa.constructor); // function Object() { [native code] }
我们发现第二种情况下,我们通过这种方式给构造函数添加原型属性和方法,改变了其原型属性,因此对象的constructor指向也改变了。这时就需要修正其constructor属性。
function aaa(){}
aaa.prototype = {
name : "sean",
age : 21
};
aaa.prototype.constructor = aaa;
var Oa = new aaa();
console.log(Oa.constructor); // function aaa(){}
修正过后的对象的constructor仍然指向其对象的构造函数。上面的jQuery.prototype中的constructor也是起相同的作用。
2、toArray(): 转数组
该方法就是将获取的json对象转成数组。先来看一下其用法:
<div>1</div>
<div>2</div>
<div>3</div>
$(function(){
console.log($("div")); //Object[div, div, div]
console.log($("div").toArray()); // [div, div, div]
});
第一个打印出来的是一个对象,通过toArray()
方法之后转成了数组。接下来介绍一下详细的原理。
文档中对jQuery对象toArray()
方法的定义如下:
只是用了一个JavaScript中数组的一个原型方法slice()
,通过call()
函数改变其上下文运行环境,this指定了运行环境为当前对象。
再回顾一下slice()方法:slice()用于截取数组中的一部分,在只有一个参数的情况下, slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。如果有两个参数,该方法返回起始和结束位置之间的项——但不包括结束位置的项。当没有传入参数时,起始位置和结束位置将会自动变为start = 0; end = this.length;。
再仔细看一眼$("div")
获得的类数组对象:
其中存在一个length属性,正好为3,因此截取前面三个元素,然后组成数组。
3、pushStack(): JQ对象的入栈;
源码(220~231行):
pushStack: function( elems ) {
// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
// Return the newly-formed element set
return ret;
},
pushStack()方法在jQuery外部用到的比较少,但是在jQuery内部确实经常用到,结合文档中的注释我们来逐行分析一下:
var ret = jQuery.merge( this.constructor(), elems );
jQuery的merge()方法表示将两个数组或类数组对象合并,this.constructor指向构造函数jQuery(),这个行的作用就是根据传入的jQuery对象创建一个新的jQuery对象。
ret.prevObject = this;
ret.context = this.context;
为新创建的对象设置prevObject属性,这个属性会存储pushStack之前的jQuery对象,所以如果你对jQuery对象进行了多次查找操作,是可以顺着prevObject返回的。保持对前一个对象的引用。context是记录上下文,如果不存在多个window,可以暂时不理会。最后返回ret。、
举例说明一下pushStack()的使用:
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
$("#div1").pushStack($("#div2")).css("background","red");
上述程序最终是把div2
的背景颜色变成红色。如果我们又要在此基础上改变div1
的背景色呢?我们知道先从栈里弹出来的是div2
,根据前面的分析,div2
通过prevObject属性保持了对div1
的引用,因此如果我们需要改变div1
的背景色,下面可以实现:
$("#div1").pushStack($("#div2")).prevObject.css("background","red");
当然这种方法是只是用于说明参数,实际应用中,我们是不会写成这样。除了prevObject属性,还有一个方法,也能达到这个效果,就是end()方法,该方法一般与pushStack()方法配套使用。
4、end(): 返回集合前一个状态
源码(271~273行):
end: function() {
return this.prevObject || this.constructor(null);
},
源码只有一行,就是返回prevObject 属性引用的对象,如果没有,则返回空对象。下面的写法也能达到上面改变div1
背景色的效果:
$("#div1").pushStack($("#div2")).end().css("background","red");
5、slice(): 集合的截取
源码(247~249行):
slice: function() {
return this.pushStack( core_slice.apply( this, arguments ) );
},
我们发现slice()方法就用到了pushStack()方法,主要就是利用JavaScript的原生slice()方法来对类数组对象进行截取,然后在进行入栈操作。我们以例子来说明:还是上面的三个div,我们进行以下操作:
$("div").slice(1,3).css("background","red");
这样就是将第二个和第三个div的背景色变成红色。具体过程是:首先$("div")
获取到的是三个div,slice(1,3)
操作就是截取第二个和第三个div,然后对其进行入栈操作,所以这时候,在栈最外层的就是截取的第二个和第三个div,css()也是对这两个div起作用。
既然是pushStack()操作,那么当然可以配套end()使用,后面加上end(),就是对$("div")
获取到的是三个div进行操作了,下面语句是改变三个div的颜色:
$("div").slice(1,3).css("background","red").end().css("color","yellow");
init(): 初始化以及管理参数,也就是选择器的处理,是jQuery中比较重要的一部分,后续会专门进行分析。
下一章会对get()和eq()进行分析和比较。