欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

jQuery 源码分析(二) 入口模块

程序员文章站 2022-06-14 09:44:23
jQuery返回的对象本质上是一个JavaScript对象,而入口模块则可以保存对应的节点的引用,然后供其它模块操作 我们创建jQuery对象时可以给jQuery传递各种不同的选择器,如下: false ;返回一个空jQuery对象 DOM节点 ;返回包含该DOM元素引用的jQuery对象。 bod ......

jquery返回的对象本质上是一个javascript对象,而入口模块则可以保存对应的节点的引用,然后供其它模块操作

我们创建jquery对象时可以给jquery传递各种不同的选择器,如下:

  false        ;返回一个空jquery对象

  dom节点      ;返回包含该dom元素引用的jquery对象。

  body        ;字符串'body',返回包含body元素引用的jquery对象

  单独标签      ;调用document.createelement创建标签对应的dom元素

  较复杂的html代码  ;调用jquery.buildfragment创建元素

  函数        ;是$(document).ready(function)的简写,等到dom加载完毕后再执行,后面有几篇专门介绍

例如:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>document</title>
    <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
</head>
<body>
    <p id="p">123</p>
    <script>
        console.log( $(false) )
        console.log( $(p) )
        console.log( $('body') )
        console.log( $('<p>123</p>') )
        $(function(){console.log('dom loaded')}) 
    </script>
</body>
</html>

输出如下:

jQuery 源码分析(二) 入口模块

输出的五条信息分别对应上面的五个输出,第一条为空jquery对象,第二条为包含p元素的jquery对象,第三条为包含body节点引用的jquery对象,第四条为jquery创建的未挂载到dom的jquery对象,第五条就直接输出信息的,对应着例子的$(function(){})对象

 

 源码分析


 writer by:大沙漠 qq:22969969

 入口模块就是上一篇文章分析的jquery内部的jquery.fn.init函数,该函数会通过参数的不同来做不同的实现,如下:

  init: function( selector, context, rootjquery ) {           //负责解析参数selector和context的类型,并执行相应的逻辑
    var match, elem, ret, doc;

    // handle $(""), $(null), or $(undefined)
    if ( !selector ) {                                                        //selector是"",null,undefined和false的等可以转换为false的情况下,对应上面的第一个jquery实例
      return this;
    }

    // handle $(domelement)
    if ( selector.nodetype ) {                                                //selector有属性nodetype,则认为selector是dom元素,例如:$(document.getelementbyid('d')),对应上面的第二个jquery实例
      this.context = this[0] = selector;
      this.length = 1;
      return this;
    }

    // the body element only exists once, optimize finding it
    if ( selector === "body" && !context && document.body ) {               //如果参数selector是字符串'body',且context为空,如:$('body'),对应上面的第三个jquery实例
      this.context = document;
      this[0] = document.body;
      this.selector = selector;
      this.length = 1;
      return this;
    }

    // handle html strings
    if ( typeof selector === "string" ) {                                   //参数selector是字符串形式
      // are we dealing with html string or an id?
      if ( selector.charat(0) === "<" && selector.charat( selector.length - 1 ) === ">" && selector.length >= 3 ) {       //如果参数selector以"<"开头、以">"结尾,且长度大于等于3
        // assume that strings that start and end with <> are html and skip the regex check   
        match = [ null, selector, null ];                                                                                     //则假设这个字符串是html片段,跳过正则quickexpr的检查。注意这里仅仅是假设,并不一定表示它是真正合法的html代码

      } else {
        match = quickexpr.exec( selector );                                                                               //否则用quickexpr来检测参数selector是否为稍微复杂一点的代码,
      }

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

        // handle: $(html) -> $(array)
        if ( match[1] ) {
          context = context instanceof jquery ? context[0] : context;
          doc = ( context ? context.ownerdocument || context : document );

          // if a single string is passed in and it's a single tag
          // just do a createelement and skip the rest
          ret = rsingletag.exec( selector );

          if ( ret ) {                                                      //如果参数selector是单独标签比如$('<p></p>');
            if ( jquery.isplainobject( context ) ) {
              selector = [ document.createelement( ret[1] ) ];
              jquery.fn.attr.call( selector, context, true );

            } else {
              selector = [ doc.createelement( ret[1] ) ];
            }

          } else {
            ret = jquery.buildfragment( [ match[1] ], [ doc ] );
            selector = ( ret.cacheable ? jquery.clone(ret.fragment) : ret.fragment ).childnodes;
          }

          return jquery.merge( this, selector );

        // handle: $("#id")
        } else {                                                            //参数selector是"#id"格式,如:$('#p1')
          elem = document.getelementbyid( match[2] );

          // check parentnode to catch when blackberry 4.6 returns
          // nodes that are no longer in the document #6963
          if ( elem && elem.parentnode ) {
            // handle the case where ie and opera return items
            // by name instead of id
            if ( elem.id !== match[2] ) {
              return rootjquery.find( selector );
            }

            // otherwise, we inject the element directly into the jquery object
            this.length = 1;
            this[0] = elem;
          }

          this.context = document;
          this.selector = selector;
          return this;
        }

      // handle: $(expr, $(...))
      } else if ( !context || context.jquery ) {
        return ( context || rootjquery ).find( selector );

      // handle: $(expr, context)
      // (which is just equivalent to: $(context).find(expr)
      } else {
        return this.constructor( context ).find( selector );
      }

    // handle: $(function)
    // shortcut for document ready
    } else if ( jquery.isfunction( selector ) ) {                           //如果参数selector是函数,则认为是绑定ready事件,从这里可以看出$(function) 是$(document).ready(function)的简写,这里对应上面的第五个jquery实例
      return rootjquery.ready( selector );
    }

    if ( selector.selector !== undefined ) {
      this.selector = selector.selector;
      this.context = selector.context;
    }

    return jquery.makearray( selector, this );
  },

这样jquery实例就获取到了对应的dom节点的引用,之后就可以用底层模块或功能模块进行操作了。