jQuery 源码分析2: jQuery.fn.init

  1 //jQuery.fn.intit 中使用到的外部变量:
  2 
  3 // 判断是否为HTML标签或#id
  4 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/;
  5 
  6 // window.document的jQuery对象
  7 rootjQuery = jQuery(window.document);
  8 
  9 // 判断是否为HTML标签
 10 rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
 11 
 12 init = jQuery.fn.init = function( selector, context ) {
 13           var match, elem;
 14 
 15           // 处理空selector $(""), $(null), $(undefined), $(false)
 16           if ( !selector ) {
 17                return this;          // 返回空jQuery对象
 18           }
 19           // 处理 HTML 字符串
 20           if ( typeof selector === "string" ) {
 21                if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
 22                     // 如果头尾含有 "<", ">"则跳过正则表达式检查
 23                     match = [ null, selector, null ];
 24                } else {
 25                     match = rquickExpr.exec( selector );     // 使用正则表达式检查是否为#id或HTML标签
 26                }
 27                // 确定是一个html标签,或为#id时没有特定的上下文
 28                if ( match && (match[1] || !context) ) {
 29                      // HANDLE: $(html) -> $(array)
 30                     if ( match[1] ) {
 31                          context = context instanceof jQuery ? context[0] : context;
 32                          // jQuery.merge把jQuery.parseHTML的返回值合并到this上
 33                          // jQuery.parseHTML将HTML字符串转换为一个DOM节点的集合
 34                          // 如果context不为空则以conext节点为上下文来创建HTML片段
 35                          // jQuery.parseHTML中的参数true表明保留HTML字符串中的脚本
 36                          // 如果parseHTML方法不存在则会抛出异常
 37                          jQuery.merge( this, jQuery.parseHTML(
 38                               match[1],
 39                               context && context.nodeType ? context.ownerDocument || context : document,
 40                               true
 41                          ) );
 42                           // jQuery(html, attributes),example
 43                          // $( "<div></div>", {
 44                          //      "class": "my-div",
 45                          //      on: { touchstart: function( event ) {// Do something}
 46                          // }
 47                          // })
 48                          // rsingleTag检测字符串时候为一个HTML tag
 49                          // jQuery.isPlainObject 判断context是否为纯粹的对象字面量
 50                          // 纯粹对象字面量表明这个对象是有new或{}创建的,它有构造器,有原型链继承,但要排除window或DOM对象
 51 
 52                          // 如果context不是纯粹对象字面量,for in 语句操作可能会出错
 53                          if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
 54                               for ( match in context ) {
 55                                    // 调用自身的方法
 56                                    if ( jQuery.isFunction( this[ match ] ) ) {
 57                                         this[ match ]( context[ match ] );
 58                                     // 设置属性
 59                                    } else {
 60                                         this.attr( match, context[ match ] );
 61                                    }
 62                               }
 63                          }
 64                           return this;
 65                      // $('#id') 选择id
 66                     } else {
 67 
 68                          // 直接利用document的方法来说实现
 69                          elem = document.getElementById( match[2] );
 70                           // Check parentNode to catch when Blackberry 4.6 returns
 71                          // nodes that are no longer in the document #6963
 72                          // Blackberry4.6 返回时有parentNode
 73                          if ( elem && elem.parentNode ) {
 74 
 75                               // IE和Opera的返回对象是第一个name符合的对象
 76                               if ( elem.id !== match[2] ) {     // 如果ID错误,在rootjQuery中用find查找
 77                                    return rootjQuery.find( selector );
 78                               }
 79                                // 如果不存在这个节点,则插入一个
 80                               this.length = 1;
 81                               this[0] = elem;
 82                          }
 83                           this.context = document;     // 添加上下文
 84                          this.selector = selector;    // 更改选择器为id
 85                          return this;
 86                     }
 87                 // 选择器表达式: $(expr, $(...))
 88 
 89                // 如果context为空或context是一个jQuery对象,jQuery.jquery存放version信息
 90                } else if ( !context || context.jquery ) {
 91                     return ( context || rootjQuery ).find( selector );
 92                 // 选择器表达式: $(expr, context)
 93                // 等同于: $(context).find(expr)
 94                } else {        // 利用jQuery构造器调用context
 95                     return this.constructor( context ).find( selector );
 96                }
 97            // $(a_node), 一个DOM节点元素
 98           } else if ( selector.nodeType ) {     // 直接把该节点添加到this上
 99                this.context = this[0] = selector;
100                this.length = 1;
101                return this;
102            // selector 是一个function, 调用jQuery.ready(func) 的快捷方式
103           } else if ( jQuery.isFunction( selector ) ) {
104                return typeof rootjQuery.ready !== "undefined" ?
105                     rootjQuery.ready( selector ) :
106                     // 如果ready方法不存在,则立即执行
107                     selector( jQuery );
108           }
109            if ( selector.selector !== undefined ) {     // 如果选择器包含其他属性,赋值给this的同名属性
110                this.selector = selector.selector;
111                this.context = selector.context;
112           }
113           
114 
115           // 将selector合并到this上
116           return jQuery.makeArray( selector, this );
117      };

 

 
 
 
     init执行过程:
  • 处理空selector,相当于返回jQuery方法接口
  • 判断HTML字符串
    • HTML字符或#id
      • 单独HTML标签,创建DOM对象并插入
      • #id,使用document.getElementById获取DOM对象
    • 选择器表达式,使用$.find
  • 函数,注册到ready或立即执行
  • DOM对象,直接返回
 
可以看到init初始化一个jQuery对象,根据形参来搜索或建立一个DOM对象(又或者是执行jQuery.ready方法),并将该对象返回。
jQuery.fn.init的实现十分精明,在JavaScript中实现了方法的重载,让API调用变得更为简单方便。
过程中有针对浏览器兼容性的处理、纯粹对象判断,用来保证运行的可靠性和稳定性,这部分十分值得研读和学习。


posted @ 2015-07-22 20:29  elcarim  阅读(749)  评论(0编辑  收藏  举报