zoukankan      html  css  js  c++  java
  • jQuery 1.6 源码学习(三)——core.js[3]之init方法

    不得不说,jQuery现在的版本更新速度大有朝chrome看齐的趋势,看来chrome的版本更新价值观很有影响力,github上已经是 1.7版了,不过官方已发布依然是1.6.1,不过想来这些版本内核现在应该是很稳定了,所以学习的时候也不考虑那么多细节了,直接down最新版来啃!

    在分析core的基本框架的时候已经弄清了,jQuery的实例对象是通过new init方法来返回的,那么init方法便是jQuery的核心方法了,也是jQuery的对外接口jQuery()(即$())的内部实现,熟悉 jQuery的童鞋应该知道除了在构建对象时封装DOM元素为类数组的jQuery实例对象,jQuery()方法也可以通过几种不同的调用方式达到不同 的效果,接下来看看源代码详细的分析:

    init: function( selector, context, rootjQuery ) {
        var match, elem, ret, doc;
        // 分支1 在没有指定选择器的情况下,直接返回本身
        // Handle $(""), $(null), or $(undefined)
        if ( !selector ) {
            return this;
        }
        // 分支2 ,当传递单个DOM元素时,直接将其作为jQuery数组的第一个元素 同样,其context也设置为该元素
        // Handle $(DOMElement)
        if ( selector.nodeType ) {
            this.context = this[0] = selector;
            this.length = 1;
            return this;
        }
        // 分支3 因为body元素在一个页面只有一个 因此优化body 访问,context此时设置为document
        // The body element only exists once, optimize finding it
        if ( selector === "body" && !context && document.body ) {
            this.context = document;
            this[0] = document.body;
            this.selector = selector;
            this.length = 1;
            return this;
        }
        // 分支4 处理HTML字符串,此时又分成如下两种情况:
        // 1 : 形如<a></a>的html代码
        // 2 : 形如#xxx的ID选择器
        // Handle HTML strings
        if ( typeof selector === "string" ) {
            // 此处为一个优化,即直接判断第一个字符和最后一个字符是不是<>对已经总字符数大于3个,
            // 在这种条件下假设HTML字符串为正确的,因此略去了正则匹配
            // Are we dealing with HTML string or an ID?
            if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
                // Assume that strings that start and end with <> are HTML and skip the regex check
                match = [ null, selector, null ];
     
            } else {
                // 此正则表达式用来匹配HTML字符串或者ID(#xxx)选择器
                // 且该表达式并不完整验证字符串是否正确
                // 注:quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/
                match = quickExpr.exec( selector );
            }
            // 如果为形如"#xxx"的ID选择器,捕获组1则为undefined(即未匹配html字符串成功),
            // context的指定则会导致调用find方法
            // Verify a match, and that no context was specified for #id
            if ( match && (match[1] || !context) ) {
                // 此时处理html代码
                // HANDLE: $(html) -> $(array)
                if ( match[1] ) {
                    context = context instanceof jQuery ? context[0] : context;
                    doc = (context ? context.ownerDocument || context : document);
                    // 处理单个标签情况, 形如 $("<div>") 或 $("<a></a>")
                    // 注: rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/
                    // 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 ) {
                        if ( jQuery.isPlainObject( context ) ) {
                            selector = [ document.createElement( ret[1] ) ];
                            // 现在attr方法和css方法在底层调用了access方法,此方法的分析先搁置一下,
                            // 在创建HTML代码时,context用来为创建的对象设置其指定的属性
                            jQuery.fn.attr.call( selector, context, true );
     
                        } else {
                            selector = [ doc.createElement( ret[1] ) ];
                        }
     
                    } else {
                        //非单个标签时将使用buildFragmenty来创建文档片段,
                        // 该方法位于manipulation.js中,属于内部方法,以后分析
                        ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
                        //clone依然位于manipulation.js中,深度复制一个对象
                        // 此处将selector设置为文档片段的子节点
                        selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
                    }
                    //merge方法用于合并两个数组,在这里会将我们创建的文档片段或者元素合并到this中(即jQuery实例对象中)
                    return jQuery.merge( this, selector );
                // HANDLE: $("#id")
                } else {
                    // 捕获组2是id值
                    elem = document.getElementById( match[2] );
                    // 一个bug,参见 http://bugs.jquery.com/ticket/6963
                    // Check parentNode to catch when Blackberry 4.6 returns
                    // nodes that are no longer in the document #6963
                    if ( elem && elem.parentNode ) {
                        // IE和opera返回name而不是ID,此时将调用find方法查找元素
                        // Handle the case where IE and Opera return items
                        // by name instead of ID
                        if ( elem.id !== match[2] ) {
                            return rootjQuery.find( selector );
                        }
                        // 否则直接将DOM元素插入到jQuery实例对象中
                        // 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, $(...))
            // 处理类似于$("div#div1",$("div#div2"))这种情况时,将递归查找,等价于$("divdiv2").find("div#div1");
            } else if ( !context || context.jquery ) {
                return (context || rootjQuery).find( selector );
     
            // 这种情况是我们处理时最普遍的情况,依然将调用find方法,在选择器代码中再做分析
            // HANDLE: $(expr, context)
            // (which is just equivalent to: $(context).find(expr)
            } else {
                return this.constructor( context ).find( selector );
            }
     
        // HANDLE: $(function)
        // Shortcut for document ready
        // 分支5 处理ready方法,$(fn)的情况
        } else if ( jQuery.isFunction( selector ) ) {
            return rootjQuery.ready( selector );
        }
        //防止$($("xxx"))这种情况处理时发生异常
        if (selector.selector !== undefined) {
            this.selector = selector.selector;
            this.context = selector.context;
        }
        //将jQuery类数组转化为一个真正的数组([xx,xx])
        return jQuery.makeArray( selector, this );
    },
    

     如代码中注释所言,jQuery对象就是这样一点点构建起来的,当然作为选择器的核心方法find留到后面再做分析,这次的分析先告一段落,下次将会看看jQuery是如何实现隐式迭代和链式调用的。

  • 相关阅读:
    GCD介绍(二): 多核心的性能
    GCD介绍(一): 基本概念和Dispatch Queue
    iOS 中如何监测某段代码运行的时间
    DSOframer 无法正常加载的解决方案
    Hexo 官方主题 landscape-plus 优化
    在 Parallels Desktop 中,全屏模式使用 Win7,唤醒时黑屏
    VS2015 企业版不支持 JavaScript 语法高亮、智能提醒
    解决 Boot Camp 虚拟机升级到 Windows 10 后 Parallels Desktop 不能识别的问题
    利用SkyDrive Pro 迅速批量下载SharePoint Server 上已上传的文件
    SharePoint Server 2013 让上传文件更精彩
  • 原文地址:https://www.cnblogs.com/firstdream/p/2342670.html
Copyright © 2011-2022 走看看