jQuery.API源码深入剖析以及应用实现(1) - 核心函数篇

简介: 前言 Jquery(http://jquery.com/)是一个轻量级,快速简洁的Javascript框架,它的容量小巧,简洁和简短的语法,容易记;用户能更方便地处理HTML DOM、Events、实现动画效果,并且提供Ajax的支持。

前言

Jquery(http://jquery.com/)是一个轻量级,快速简洁的Javascript框架,它的容量小巧,简洁和简短的语法,容易记;用户能更方便地处理HTML DOMEvents、实现动画效果,并且提供Ajax的支持。目前最新版本为 jQuery 1.3.1(http://jqueryjs.googlecode.com/files/jquery-1.3.1.js),这系列文章将对该版本的源码进行阐述。

现在开始本系列的第一篇,Jquery核心函数,内容主要包括:

 

分析

1. 在Jquery的应用开发中,我们经常看到这样的代码:

$( " div .container " ).css( " display " , " none " );  // 将div节点下样式值为container的节点设置为不显示
var  width  =  $( " div .container " ).width();  // 得到div节点下样式值为container的宽度
var  html  =  $(document.getElementById( " result " )).html();  // 得到id为result的节点的innerHTML值
$( " #result " , document.forms[ 0 ]).css( " color " " red " );  // 将在第一个Form节点下id为result的字体颜色设置为红色
$( " <div>hello,world</div> " ).appendTo( " #result " );  // 将HTML字符串信息 内部追加到 id为result的节点末尾

那么$(...)里面的参数,Jquery API中是怎样辨认参数是表达式,id,HTML字符串,还是DOM元素呢?

现在我们来深入剖析Jquery源码。


2. 这里,我先来做个测试,我将Jquery API简化为这样的代码:

( function (){
    
var  window  =   this ,
    
    jQuery 
=  window.jQuery  =  window.$  =   function (selector, context){
        
return   new  jQuery.fn.init(selector, context);
    };
    
    jQuery.fn 
=  jQuery.prototype  =  {
        init : 
function (selector, context) {
            alert(selector); 
// 弹出警告框
        }
    };
})();
window.onload 
=   function () {
    $(
" div .container " );  // 得到“div . container”
    $( " #result " );  // 得到“#result”
    $( " <div>hello,world</div> " );  // 得到“<div>hello,world</div>”
    $(document.getElementById( " result " ));  // 得到“[object]”
}

从这里我们可以得出,实际上$里面的参数(表达式字符串,ID字符串,HTML字符串,DOM对象),主要就是在init方法中各自实现它们自己的逻辑

现在列出init方法的具体实现:

    init function ( selector, context ) {
        
//  Make sure that a selection was provided
        selector  =  selector  ||  document;

        
//  Handle $(DOMElement)
         if  ( selector.nodeType ) {
            
this [ 0 =  selector;
            
this .length  =   1 ;
            
this .context  =  selector;
            
return   this ;
        }
        
//  Handle HTML strings
         if  (  typeof  selector  ===   " string "  ) {
            
//  Are we dealing with HTML string or an ID?
             var  match  =  quickExpr.exec( selector );

            
//  Verify a match, and that no context was specified for #id
             if  ( match  &&  (match[ 1 ||   ! context) ) {

                
//  HANDLE: $(html) -> $(array)
                 if  ( match[ 1 ] )
                    selector 
=  jQuery.clean( [ match[ 1 ] ], context );

                
//  HANDLE: $("#id")
                 else  {
                    
var  elem  =  document.getElementById( match[ 3 ] );

                    
//  Handle the case where IE and Opera return items
                     //  by name instead of ID
                     if  ( elem  &&  elem.id  !=  match[ 3 ] )
                        
return  jQuery().find( selector );

                    
//  Otherwise, we inject the element directly into the jQuery object
                     var  ret  =  jQuery( elem  ||  [] );
                    ret.context 
=  document;
                    ret.selector 
=  selector;
                    
return  ret;
                }

            
//  HANDLE: $(expr, [context])
             //  (which is just equivalent to: $(content).find(expr)
            }  else
                
return  jQuery( context ).find( selector );

        
//  HANDLE: $(function)
         //  Shortcut for document ready
        }  else   if  ( jQuery.isFunction( selector ) )
            
return  jQuery( document ).ready( selector );

        
//  Make sure that old selector state is passed along
         if  ( selector.selector  &&  selector.context ) {
            
this .selector  =  selector.selector;
            
this .context  =  selector.context;
        }

        
return   this .setArray(jQuery.makeArray(selector));
    }

 

3. 现在分析 表达式,id,HTML字符串,DOM元素等等各自的实现:

1)形如 $(document.getElementById("result")) 【jQuery(elements)】DOM元素的实现,通过init方法中的以下代码:

  //  Handle $(DOMElement)
   if  ( selector.nodeType ) {
   
this [ 0 =  selector;
   
this .length  =   1 ;
   
this .context  =  selector;
   
return   this ;
  }

selector.nodeType判断当selector为元素节点时,将length置为1,并且赋值于context,实际上context作为init的第二个参数,它意味着它的上下文节点就是selector该点,返回它的$(...)对象。

2)形如 $("<div>hello,world</div>") 【jQuery(html,[ownerDocument])】HTML字符串的实现,通过init方法中的以下代码:

//  判断selector为字符串
if  (  typeof  selector  ===   " string "  ) {
    
//  quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/
     //  利用检查正则表达式HTML字符串还是元素ID字符串
     var  match  =  quickExpr.exec( selector );
    
    
if  ( match  &&  (match[ 1 ||   ! context) ) {

        
//  处理HTML字符串
         if  ( match[ 1 ] )
            selector 
=  jQuery.clean( [ match[ 1 ] ], context );

        
//  处理形如$("#id")
         else  {
            
//  
        }
    
    } 
    
//  处理 形如 $("div .container")的表达式字符串
     else
        
//  

}
 
//  处理 形如 $(function) , $(document).ready(function(){})的表示
else   if  ( jQuery.isFunction( selector ) ) {

}
//  

关键看到这样的一句代码,selector = jQuery.clean( [ match[1] ], context ); 继续查看clean都做了些什么:

img_1c53668bcee393edac0d7b3b3daff1ae.gif Code

这么长的一串代码 实际上最后访问的是一个ret为变量的数组,而数组中的元素变为以DOM元素的对象,而它的innerHTML正好就是刚才的HTML字符串。


3)形如 $("#result") 【jQuery(expression,[context])】ID字符串的实现,通过init方法中的以下代码:

//  处理形如$("#result")
else  {
    
//  match[3]得到ID的值如:result
     var  elem  =  document.getElementById( match[ 3 ] );

    
if  ( elem  &&  elem.id  !=  match[ 3 ] )
        
return  jQuery().find( selector );

    
//  调用jQuery(elements)方式
     var  ret  =  jQuery( elem  ||  [] );
    
//  默认上下文DOM为window.document
    ret.context  =  document;
    ret.selector 
=  selector;
    
return  ret;
}

根据match[3]可以得到DOM对象elem,并且调用2)介绍的jQuery(elements),最后返回一个ret为变量的jquery对象。


4)形如 $("div .container") 【jQuery(expression,[context])】表达式字符串的实现,通过init方法中的以下代码:

//  处理 形如 $("div .container")的表达式字符串
else
  
return  jQuery( context ).find( selector );

关键看到这样的一句代码,jQuery().find( selector ); 继续查看find都做了些什么:

find:  function ( selector ) {
    
//  当表达式不包含“,”符号时候
     if  (  this .length  ===   1   &&   ! / , / .test(selector) ) {
        
var  ret  =   this .pushStack( [],  " find " , selector );
        ret.length 
=   0 ;
        jQuery.find( selector, 
this [ 0 ], ret );
        
return  ret;
    } 
    
//  当表达式包含“,”符号时候
     else  {
        
var  elems  =  jQuery.map( this function (elem){
            
return  jQuery.find( selector, elem );
        });

        
return   this .pushStack(  / [^+>] [^+>] / .test( selector )  ?
            jQuery.unique( elems ) :
            elems, 
" find " , selector );
    }
}

先看下表达式不包含“,”符号的时候,调用pushStack方法,方法为:

//  将一系列元素推入栈中
pushStack:  function ( elems, name, selector ) {

    
var  ret  =  jQuery( elems );

    
//  将上个对象的引用推入栈中
    ret.prevObject  =   this ;

    ret.context 
=   this .context;

    
//  关键字为find时,在原有selector的基础上,继续增加selector
     //  如 $("div").find("p") 意思就是 $("div p")
     if  ( name  ===   " find "  )
        ret.selector 
=   this .selector  +  ( this .selector  ?   "   "  :  "" +  selector;
    
else   if  ( name )
        ret.selector 
=   this .selector  +   " . "   +  name  +   " ( "   +  selector  +   " ) " ;

    
//  返回最新的Jquery对象
     return  ret;
}

注意这里看到 ret.prevObject = this;  这个方法在$(...).andSelf()$(...).end()中调用,对于筛选或查找后的元素,返回前一次元素状态它是很有用的。

接着调用 jQuery.find( selector, this[0], ret ); ,首先我们看到有这样的几句代码:

jQuery.find  =  Sizzle;
jQuery.filter 
=  Sizzle.filter;
jQuery.expr 
=  Sizzle.selectors;
jQuery.expr[
" : " =  jQuery.expr.filters;
//  
window.Sizzle  =  Sizzle;

jQuery.find方法转去调用全局的Sizzle对象了(实际上这里运用到了Javascript设计模式中的适配器模式,jquery.find实际上调用的是Sizzle的对象。关于Javascript适配器模式,我将接下来的Javascript乱弹设计模式系列文章中具体叙述),Sizzle对象定义为:

img_1c53668bcee393edac0d7b3b3daff1ae.gif Code

呵呵,好长的一段代码,实际最关键的一句代码:Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
对表达式字符串进行解析,最后返回一个jQuery对象,它就是 表达式字符串 最后想要的jQuery对象。


当表达式包含“,”符号的时候,查看这样的一句代码:return this.pushStack( /[^+>] [^+>]/.test( selector ) ? jQuery.unique( elems ) : elems, "find", selector );

它的意思是当表达式字符串包含“+”,“>”作为选择器(比如$("form > input") 或者 $("label + input") )的时候,将作为jQuery.map返回值的elems数组删除重复的元素,这个是有必要的。
最后也是返回一个jQuery对象,它就是 表达式字符串 最后想要的jQuery对象。


5)最后一点,形如 $(function) , $(document).ready(function(){})的表示,通过init方法中的以下代码来实现:

//  处理 形如 $(function) , $(document).ready(function(){})的表示
else   if  ( jQuery.isFunction( selector ) )
    
return  jQuery( document ).ready( selector );

如果判断selector是函数的话,将执行jQuery(document).ready(selector);
ready方法具体为:

ready:  function (fn) {
    
//  绑定事件监听
    bindReady();

    
if  ( jQuery.isReady )
        fn.call( document, jQuery );

    
else
        jQuery.readyList.push( fn );

    
return   this ;
}

bindReady方法将事件绑定在文档加载完毕之后,最后通过调用fn.call( document, jQuery );来激发事件的执行。

 

好了,jQuery的核心函数的原理机制就是这样的,下一篇我将谈下jQuery对象访问和数据缓存的原理机制

目录
相关文章
|
21天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
55 2
|
2月前
|
存储 缓存 搜索推荐
Lazada淘宝详情API的价值与应用解析
在电商行业,数据是驱动业务增长的核心。Lazada作为东南亚知名电商平台,其商品详情API对电商行业影响深远。本文探讨了Lazada商品详情API的重要性,包括提供全面准确的商品信息、增强平台竞争力、促进销售转化、支持用户搜索和发现需求、数据驱动决策、竞品分析、用户行为研究及提升购物体验。文章还介绍了如何通过Lazada提供的API接口、编写代码及使用第三方工具实现实时数据获取。
61 3
|
2月前
|
监控 搜索推荐 数据挖掘
淘宝 API 接口的调用频率限制是否会因应用类型而异?
淘宝API调用频率限制依应用类型而异。电商管理类如商家后台、商品批量上传工具,调用频次较高;数据分析类如市场调研、店铺分析工具,频次较严;导购推荐类如第三方导购平台、社交媒体导购应用,依据规模与信誉设定;其他如开发者测试、个人小型应用则限制较宽松。
|
19天前
|
API 开发工具 开发者
探究亚马逊国际获得AMAZON商品详情 API 接口功能、作用与实际应用示例
亚马逊提供的Amazon Product Advertising API或Selling Partner API,使开发者能编程访问亚马逊商品数据,包括商品标题、描述、价格等。支持跨境电商和数据分析,提供商品搜索和详情获取等功能。示例代码展示了如何使用Python和boto3库获取特定商品信息。使用时需遵守亚马逊政策并注意可能产生的费用。
|
24天前
|
监控 搜索推荐 安全
探究亚马逊详情API接口:开发与应用
在数字化时代,亚马逊作为全球领先的电商平台,为商家和消费者提供了丰富的商品信息和便捷的购物体验。本文深入探讨了亚马逊详情API接口的获取与运用,帮助开发者和商家实时监控商品数据、分析市场趋势、优化价格策略、分析竞争对手、构建推荐系统及自动化营销工具,从而在竞争中占据优势。文章还提供了Python调用示例和注意事项,确保API使用的安全与高效。
49 3
|
28天前
|
搜索推荐 数据挖掘 API
API接口在电商的应用及收益
本文探讨了API接口技术在电商领域的应用及其带来的收益。API接口作为连接电商平台与外部系统的桥梁,实现了高效、实时的数据交换和集成,提升了用户体验、运营效率和市场竞争力。具体应用包括库存管理、支付网关、物流跟踪、自动化业务流程、个性化推荐和精准营销等方面。通过实战案例分析,展示了亚马逊和小型电商公司如何利用API接口实现自动化管理,提高了工作效率和客户满意度。未来,API接口技术将更加注重智能化、标准化、安全性和跨界合作。
71 3
|
1月前
|
JavaScript
jQuery制作的3D冰块立方时钟动态特效源码
jQuery制作的3D冰块立方时钟动态特效源码是一段基于jQuery实现的3D魔方立方时钟效果代码,该设计非常特别,且支持数字颜色的变化,提供8款颜色选择,非常有意思,欢迎对此段代码感兴趣的朋友前来下载使用。
36 8
|
1月前
|
JavaScript
jQuery制作的网站首页宽屏导航轮播图特效源码
jQuery制作的网站首页宽屏导航轮播图特效源码是一段基于jQuery制作的可用于商城首页 微商城 互联网公司或某些电子商城的首页特效,自带有二级菜单栏、轮播图滚动、登录注册按钮等等,非常全面,欢迎对此段代码感兴趣的朋友前来下载使用。
18 4
|
1月前
|
JavaScript
jQuery实现的手风琴四季场景变换特效源码
jQuery实现的手风琴四季场景变换特效源码是一段基于jQuery实现的手风琴四季场景变换效果代码,拥有春夏秋冬四季转场特效,鼠标可放大每个季节的图像,欢迎对此段代码感兴趣的朋友前来下载使用。
25 1
|
2月前
|
JSON 供应链 API
京东商品评价API的获取和应用
京东商品评价API是电商数据分析的重要工具,帮助开发者和商家获取商品的用户评价数据,包括评分、评论内容和购买时间等。通过分析这些数据,商家可以优化产品和服务,提升客户满意度,制定更有效的营销策略。本文介绍了获取和应用京东商品评价API的详细步骤,包括注册账号、获取权限、阅读文档和编写代码调用API。示例代码展示了如何使用Python调用API并处理响应数据。
104 2