jQuery源码学习 item2-jQuery对象及其属性和方法

一、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()进行分析和比较。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值