jQuery.API源码深入剖析以及应用实现(2) - jQuery对象访问和数据缓存

简介: 前言 上篇主要介绍JQuery的核心函数的原理机制,这篇将开始介绍jQuery对象访问和数据缓存原理,主要内容包括:      分析 一、jQuery对象访问 1. 【each(callback)】 例子: HTML代码 jQuery代码 运行结果 $("img").

前言

上篇主要介绍JQuery的核心函数的原理机制,这篇将开始介绍jQuery对象访问和数据缓存原理,主要内容包括:

  

 

分析

一、jQuery对象访问

1. 【each(callback)

例子:

HTML代码 jQuery代码 运行结果
<img/><img/>

$("img").each(function(i){
   this.src = "test" + i + ".jpg";
});

[ <img src="test0.jpg" />, <img src="test1.jpg" /> ]
<img/><img/>

("img").each(function(){("img").each(function(){(this).toggleClass("example");
});

切换样式example

现在来看each方法的具体实现如下:

jQuery.fn  =  jQuery.prototype  =  {
    each: 
function ( callback, args ) {
        
return  jQuery.each(  this , callback, args );
    }
}

可以看到它返回的是全局的each方法,并且将自身jQuery对象做为参数给它,全局的each方法的具体实现如下:

//  args 作为内部成员的调用来使用
each:  function ( object, callback, args ) {
    
var  name, i  =   0 , length  =  object.length;   //  当object为jQuery对象时,length非空

    
if  ( args ) {
        
if  ( length  ===  undefined ) {
            
for  ( name  in  object )
                
if  ( callback.apply( object[ name ], args )  ===   false  )
                    
break ;
        } 
else
            
for  ( ; i  <  length; )
                
if  ( callback.apply( object[ i ++  ], args )  ===   false  )
                    
break
    
//  以下是客户端程序进行调用
    }  else  {
        
if  ( length  ===  undefined ) {
            
for  ( name  in  object )
                
if  ( callback.call( object[ name ], name, object[ name ] )  ===   false  )
                    
break ;
        } 
else
            
for  (  var  value  =  object[ 0 ];
                i 
<  length  &&  callback.call( value, i, value )  !==   false ; value  =  object[ ++ i] ){}
    } 

    
return  object;
}

现在我们关注下 for ( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} 这句代码;

其中object[0]取得jQuery对象中的第一个DOM元素,通过for循环,得到遍历整个jQuery对象中对应的每个DOM元素,通过callback.call( value,i,value); 将callback的this对象指向value对象,并且传递两个参数,i表示索引值,value表示DOM元素;其中callback是类似于 function(index, elem) { ... } 的方法。所以就得到 $("...").each(function(index, elem){ ... });

 

2. 【size()】和【length

这两个都是得到jQuery 对象中元素的个数,具体实现如下:

size:  function () {
    
return   this .length;
}

 

3. 【selector】和【context

selector返回传给jQuery()的原始选择器。

context返回传给jQuery()的原始的DOM节点内容,即jQuery()的第二个参数。如果没有指定,那么context指向当前的文档(document)。

这两个属性在上一篇文章也有提及,请参考jQuery.API源码深入剖析以及应用实现(2) - 对象访问和数据缓存 ,这里不再敖述。


4. 【get()】和【get(index)

get()取得所有匹配的 DOM 元素集合。

get(index)取得其中一个匹配的DOM元素,index表示取得第几个匹配的元素。

(this).get(0)(this)[0]等价。

现在看下get方法的具体实现如下:

get:  function ( num ) {
    
return  num  ===  undefined  ?  

        
//  当num为undefined时,返回所有匹配的DOM元素集合
        jQuery.makeArray(  this  ) : 

        
//  当num不为undefined时,返回第num+1个匹配的DOM元素
         this [ num ];
}


当不包含num时,调用jQuery.makeArray方法,具体实现如下:

makeArray:  function ( array ) {
    
var  ret  =  []; 

    
if ( array  !=   null  ){
        
var  i  =  array.length;
        
//  The window, strings (and functions) also have 'length'
         if ( i  ==   null   ||   typeof  array  ===   " string "   ||  jQuery.isFunction(array)  ||  array.setInterval )
            ret[
0 =  array;
        
else
            
while ( i )
                ret[
-- i]  =  array[i];
    } 

    
return  ret;
}

可以看出这里的array为jQuery对象,因此执行 while( i ) ret[--i] = array[i]; , 返回的是以array所有匹配的DOM元素所组成的数组。这和前面的定义相一致。

当包含num时,直接返回 this[ num ],所以这样验证了 (this).get(0)(this)[0]等价 的说明。


5. 【index(subject)】 

搜索与参数表示的对象匹配的元素,并返回相应元素的索引值。

例子

HTML代码 jQuery代码
<div id="foobar"><div></div><div id="foo"></div></div>

("div").index(('#foobar')[0]) // 0
("div").index(('#foo')[0]) // 2
("div").index(('#foo')) // -1

现在看下index方法的具体实现如下:

index:  function ( elem ) { 

    
return  jQuery.inArray(
        
//  如果elem为一个jQuery对象,那么得到的是第一个匹配的DOM元素
        elem  &&  elem.jquery  ?  elem[ 0 ] : elem
    , 
this  );
}

继续查看jQuery.inArray方法,具体实现如下:

inArray:  function ( elem, array ) {
    
for  (  var  i  =   0 , length  =  array.length; i  <  length; i ++  )
    
//  Use === because on IE, window == document
         if  ( array[ i ]  ===  elem )
            
return  i; 

    
return   - 1 ;
}

一目了然,返回elem的索引值。


二、数据缓存

1. 【data(name)】和【data(name,value)

data(name)返回元素上储存的相应名字的数据,可以用data(name, value)来设定。

data(name,value)在元素上存放数据,同时也返回value。

例子

HTML代码 jQuery代码
<div></div>

("div").data("blah");//undefined("div").data("blah", "hello"); // blah设置为hello
("div").data("blah");//hello("div").data("blah", 86); // 设置为86
("div").data("blah");//86("div").removeData("blah"); //移除blah
$("div").data("blah"); // undefined

<div></div>

("div").data("test",first:16,last:"pizza!");("div").data("test").first //16;
$("div").data("test").last //pizza!;

现在来看看data方法的具体实现:

jQuery.fn.extend({
    data: 
function ( key, value ){
        
var  parts  =  key.split( " . " );
        parts[
1 =  parts[ 1 ?   " . "   +  parts[ 1 ] :  ""

        
if  ( value  ===  undefined ) {
            
var  data  =   this .triggerHandler( " getData "   +  parts[ 1 +   " ! " , [parts[ 0 ]]); 

            
if  ( data  ===  undefined  &&   this .length )
                data 
=  jQuery.data(  this [ 0 ], key ); 

            
return  data  ===  undefined  &&  parts[ 1 ?
                
this .data( parts[ 0 ] ) :
                data;
        } 
else
            
return   this .trigger( " setData "   +  parts[ 1 +   " ! " , [parts[ 0 ], value]).each( function (){
                jQuery.data( 
this , key, value );
            });
    }, 

    removeData: 
function ( key ){
        
return   this .each( function (){
            jQuery.removeData( 
this , key );
        });
    }
});


当我们要在元素上存放数据的时候,比如 $("div").data("blah","hello"); 将执行这句代码:

return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){jQuery.data( this, key, value );});

我们看下jQuery.data(this,key,value);这句代码,继续展开jQuery.data方法的具体实现以及相关其他代码:

function  now(){
    
return   + new  Date;
}
var  expando  =   " jQuery "   +  now(), uuid  =   0 , windowData  =  {}; 

jQuery.extend({
    cache: {},
    data: 
function ( elem, name, data ) {
        elem 
=  elem  ==  window  ?
            windowData :
            elem; 

        
var  id  =  elem[ expando ]; 

        
//  在元素上产生唯一的ID
         if  (  ! id )
            id 
=  elem[ expando ]  =   ++ uuid; 

        
//  当我们试着访问一个键是否含有值的时候,如果不存在jQuery.cache[id]值, 初始化jQuery.cache[id]值
         if  ( name  &&   ! jQuery.cache[ id ] )
            jQuery.cache[ id ] 
=  {}; 

        
//  防止一个undefined的值覆盖jQuery.cache对象
         if ( data !==  undefined )
            jQuery.cache[ id ][ name ] 
=
 data; 

        
return name ?
            jQuery.cache[ id ][ name ] :
            id;
    }
});

其中这句代码

if ( data !== undefined )
            jQuery.cache[ id ][ name ] = data;

将data存储在cache对象中。

当我们需要返回元素上储存的相应名字的数据的时候,比如 $("div").data("blah"); 主要将执行这句代码:

data = jQuery.data( this[0], key );

最后将返回一个保存在 jQuery.cache[ id ][ name ] 中的数据。


2. 【removeData(name)

在元素上移除存放的数据。具体实现如下:

removeData:  function ( key ){
    
return   this .each( function (){
        jQuery.removeData( 
this , key );
    });
}

继续展开jQuery.removeData方法的具体实现:

removeData:  function ( elem, name ) {
    elem 
=  elem  ==  window  ?
        windowData :
        elem; 

    
var  id  =  elem[ expando ]; 

    
if  ( name ) {
        
//  elem是否存在元素cache
         if  ( jQuery.cache[ id ] ) {
            
//  移除一个具有特定键的元素数据
             delete  jQuery.cache[ id ][ name ]; 

            
//  将键值置空,准备移除元素cache
            name  =   ""

            
for  ( name  in  jQuery.cache[ id ] )
                
break

            
if  (  ! name )
                jQuery.removeData( elem );
        } 

    } 
else  {
        
//  Clean up the element expando
         try  {
            
delete  elem[ expando ];
        } 
catch (e){
            
//  IE has trouble directly removing the expando
             //  but it's ok with using removeAttribute
             if  ( elem.removeAttribute )
                elem.removeAttribute( expando );
        } 

        
//  完全移除元素cache
         delete  jQuery.cache[ id ];
    }
}

通过调用 delete jQuery.cache[ id ][ name ];  和 delete jQuery.cache[ id ];,移除所有该元素上的cache数据;


3. 【queue([name])】,【queue([name],callback)】和【queue([name],queue

例子

HTML 代码 jQuery 代码
  <style>
        div { margin:3px; width:40px; height:40px;
        position:absolute; left:0px; top:30px;
        background:green; display:none; }
        div.newcolor { background:blue; }
        span { color:red; }
        </style>
        <button id="show">Show Length of Queue</button>
        <span></span>
        <div></div>
$("#show").click(function () {
        var n = $("div").queue("fx");
        $("span").text("Queue length is: " + n.length);
        });
        function runIt() {
        $("div").show("slow");
        $("div").animate({left:'+=200'},2000);
        $("div").slideToggle(1000);
        $("div").slideToggle("fast");
        $("div").animate({left:'-=200'},1500);
        $("div").hide("slow");
        $("div").show(1200);
        }
        runIt();
  <style>
        div { margin:3px; width:40px; height:40px;
        position:absolute; left:0px; top:30px;
        background:green; display:none; }
        div.newcolor { background:blue; }
        </style>
        Click here...
        <div></div>
$(document.body).click(function () {
        $("div").show("slow");
        $("div").animate({left:'+=200'},2000);
        $("div").queue(function () {
        $(this).addClass("newcolor");
        $(this).dequeue();
        });
        $("div").animate({left:'-=200'},500);
        $("div").queue(function () {
        $(this).removeClass("newcolor");
        $(this).dequeue();
        });
        $("div").slideUp();
        });
  <style>
        div { margin:3px; width:40px; height:40px;
        position:absolute; left:0px; top:30px;
        background:green; display:none; }
        div.newcolor { background:blue; }
        </style>
        <button id="start">Start</button>
        <button id="stop">Stop</button>
        <div></div>
  $("#start").click(function () {
        $("div").show("slow");
        $("div").animate({left:'+=200'},5000);
        $("div").queue(function () {
        $(this).addClass("newcolor");
        $(this).dequeue();
        });
        $("div").animate({left:'-=200'},1500);
        $("div").queue(function () {
        $(this).removeClass("newcolor");
        $(this).dequeue();
        });
        $("div").slideUp();
        });
          $("#stop").click(function () {
        $("div").queue("fx", []);
        $("div").stop();
        });

由于div节点产生动画效果,每条动画就调用一个jQuery.data方法,将每条动作保存在jQuery.cache中,就形成了缓存队列。至于div节点产生动画效果如何调用jQuery.data方法会在以后的章节中介绍。

请看第一行的例子,可以看到这里包含7条动作效果,也就是在还没有执行它们以前,如果调用 var n = $("div").queue("fx"); 返回一个队列对象n,查看该对象的长度,发现队列长度为7,而每执行完一条动作,队列长度就会减1。

再看第二行的例子,queue的第一个参数为一个函数,当执行完这个自定义函数后,要继续执行队列,这要调用dequeue方法。

再看第三行的例子,queue的第二个参数为一个数组,实际上它可以是一个新队列或者现有队列去替代当前队列,其中新队列或者现有队列的值和queue(callback)相同。

现在看看queue的具体实现:

queue:  function (type, data){
    
if  (  typeof  type  !==   " string "  ) {
        data 
=  type;
        type 
=   " fx " ;
    } 

    
if  ( data  ===  undefined )
    {
        
return  jQuery.queue(  this [ 0 ], type );} 

    
return   this .each( function (){
        
var  queue  =  jQuery.queue(  this , type, data );
         
if ( type  ==   " fx "   &&  queue.length  ==   1  )
            queue[
0 ].call( this );
    });
}

其中 if(typeof type !== "string") { data = type; type = "fx"; } 可以得出fx为默认的队列名称。继续查看jQuery.queue方法:

queue:  function ( elem, type, data ) {
    
if  ( elem ){ 

        type 
=  (type  ||   " fx " +   " queue "

        
var  q  =  jQuery.data( elem, type ); 

        
if  (  ! ||  jQuery.isArray(data) )
            q 
=  jQuery.data( elem, type, jQuery.makeArray(data) );
        
else   if ( data )
            q.push( data ); 

    }
    
return  q;
}

归根结底最后通过jQuery.data从jQuery.cache对象获得数据。jQuery.isArray(data) 判断是否是新队列或者现有队列数组。


4. 【dequeue([name])

从队列最前端移除一个队列函数,并执行它。

dequeue的具体实现为:

dequeue:  function (type){
    
return   this .each( function (){
        jQuery.dequeue( 
this , type );
    });
}

然后查看jQuery.dequeue方法的具体实现如下:

dequeue:  function ( elem, type ){
    
var  queue  =  jQuery.queue( elem, type ),
        fn 
=  queue.shift();
    
if ! type  ||  type  ===   " fx "  )
        fn 
=  queue[ 0 ];
    
if ( fn  !==  undefined )
        fn.call(elem);
}

可以发现最后通过 fn=queue.shift();或者fn=queue[0]得到队列的第一个元素,然后fn.call(elem);去执行它。


好了,jQuery对象访问和数据缓存的原理机制就是这样的。

目录
打赏
0
0
0
0
16
分享
相关文章
淘宝拍立淘按图搜索API接口系列的应用与数据解析
淘宝拍立淘按图搜索API接口是阿里巴巴旗下淘宝平台提供的一项基于图像识别技术的创新服务。以下是对该接口系列的应用与数据解析的详细分析
淘宝商品评论API接口系列的应用与数据解析
在电商平台中,用户评论是了解商品质量、服务水平和用户满意度的重要数据来源。淘宝作为中国最大的电商平台,提供了商品评论API接口,帮助开发者获取和分析用户评价数据。本文将介绍淘宝商品评论API接口系列的作用、使用方法,并通过示例展示如何调用API并解析返回的JSON数据。
1688 快递费用 API 接口的技术剖析与应用
1688快递费用API接口为企业和开发者提供自动化、高效化的快递费用查询服务,打破人工查询的繁琐局面。通过输入寄件与收件地址、商品重量、体积及选择快递公司等信息,接口精准计算费用并返回结果,支持中通、圆通等主流快递。输出内容包括快递费用、预估时效及附加费说明,助力电商精细化运营。Python示例代码展示了如何使用requests库发起POST请求并解析响应数据,实现费用查询自动化。
30 10
【03】支付宝支付商户申请下户到配置完整流程-对签约申请已通过商户进行开通API支付-创建应用-申请支付宝公钥-应用公钥-支付宝密钥-配合支付宝官方证书生成工具+配置完整流程-优雅草卓伊凡
【03】支付宝支付商户申请下户到配置完整流程-对签约申请已通过商户进行开通API支付-创建应用-申请支付宝公钥-应用公钥-支付宝密钥-配合支付宝官方证书生成工具+配置完整流程-优雅草卓伊凡
27 0
【03】支付宝支付商户申请下户到配置完整流程-对签约申请已通过商户进行开通API支付-创建应用-申请支付宝公钥-应用公钥-支付宝密钥-配合支付宝官方证书生成工具+配置完整流程-优雅草卓伊凡
深度解析淘宝商品评论API接口:技术实现与应用实践
淘宝商品评论API接口是电商数据驱动的核心工具,帮助开发者高效获取用户评价、画像及市场趋势。其核心功能包括多维度信息采集、筛选排序、动态更新、OAuth 2.0认证和兼容多种请求方式。通过该接口,开发者可进行商品优化、竞品分析、舆情监控等。本文详细解析其技术原理、实战应用及挑战应对策略,助力开启数据驱动的电商运营新篇章。
|
4天前
|
类似ComfyUI和Midjourney这样的文生图图生图应用的API与服务架构该怎么设计
文生图图生图应用的API与服务架构分析。或和微服务类似,但是不同。ComfyUI其 API 架构设计为我们理解此类应用提供了很好的参考模型。但距离生产级别的应用差距还有很远。
25 0
淘宝评论与商品详情数据API接口的使用与应用
商品详情数据API:获取商品的基本信息(如标题、价格、库存、描述等)。 评论数据API:获取商品的用户评价数据(如评分、评论内容、用户昵称、购买时间等)。
小红书笔记详情 API 接口的开发、应用与收益
小红书(RED)作为国内领先的生活方式分享平台,汇聚了大量用户生成内容(UGC),尤其是“种草”笔记。小红书笔记详情API接口为开发者提供了获取笔记详细信息的强大工具,包括标题、内容、图片、点赞数等。通过注册开放平台账号、申请API权限并调用接口,开发者可以构建内容分析工具、笔记推荐系统、数据爬虫等应用,提升用户体验和运营效率,创造新的商业模式。本文详细介绍API的开发流程、应用场景及潜在收益,并附上Python代码示例。
204 61
阿里巴巴热卖商品推荐 API 接口的开发、应用与收益
阿里巴巴热卖商品推荐API为开发者提供了获取平台热卖商品信息的强大工具,涵盖商品标题、价格、销量等数据。通过注册开放平台账号、申请API权限并调用接口,开发者可构建热卖商品推荐系统、数据分析工具及供应链管理系统等应用,提升用户体验与运营效率,创造新的商业模式。该API采用RESTful风格,支持多种应用场景,助力电商从业者实现创新与增值。
127 7
亚马逊详情 API 接口的开发、应用与收益
亚马逊详情API接口是亚马逊开放平台提供的强大工具,允许开发者编程获取商品的详细信息,如标题、价格、描述等。通过注册账号、申请权限并调用API,开发者可构建比价工具、推荐系统和数据分析工具等应用,提升用户体验与运营效率,创造新商业模式。本文详细介绍其开发流程、应用场景及潜在收益,并附代码示例。
50 6

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等