zoukankan      html  css  js  c++  java
  • jquery 源码分析一

    (function( global, factory ) {
    
        if ( typeof module === "object" && typeof module.exports === "object" ) {
            // For CommonJS and CommonJS-like environments where a proper window is present,
            // execute the factory and get jQuery
            // For environments that do not inherently posses a window with a document
            // (such as Node.js), expose a jQuery-making factory as module.exports
            // This accentuates the need for the creation of a real window
            // e.g. var jQuery = require("jquery")(window);
            // See ticket #14549 for more info
            module.exports = global.document ?
                factory( global, true ) :
                function( w ) {
                    if ( !w.document ) {
                        throw new Error( "jQuery requires a window with a document" );
                    }
                    return factory( w );
                };
        } else {
            factory( global );
        }
    
    // Pass this if window is not defined yet
    }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
        //jQuery code goes here
    }));

    这是1.11.0版jquery开头的一段源码,这段源码的意义是为了能够兼容一些新的js用处,如nodeJS,在上面的英文注释中已经写得很详细了,就不多做解释了。其最终还是想后面的函数传入了一个window或者类window对象和一个布尔值。

    jQuery的实例化主要由以下这段函数实现

    jQuery = function( selector, context ) {
        // The jQuery object is actually just the init constructor 'enhanced'
        // Need init if jQuery is called (just allow error to be thrown if not included)
        return new jQuery.fn.init( selector, context );
    }

    这段函数主要是通过实例化jQuery.fn.init来实现的,一模一样的参数传入。不过在分析init内容之前,有一个问题,那就是如果这样实例化的话,原先加载在jQuery.prototype上的方法就应该不能被使用,可是最后还是可以调用,这是为什么呢。。原因就是有这么一句代码:

    jQuery.fn = jQuery.prototype = {
        //some codes
    }
    //some codes
    init.prototype = jQuery.fn;

    这样使得jQuery.fn,jQuery.prototype和init.prototype引用的是同一个对象,由于对象是引用型变量,所以在这句话以后对jQuery.prototype的修改,还是会在jQuery.fn上体现出来,也会在init.prototype上出现。这样实例化以后就会得到所有jQuery方法。

    接下来就是init方面的分析了,分析如下:

      1 init = jQuery.fn.init = function( selector, context ) {
      2     var match, elem;
      3 
      4     // 处理那些为空选择的情况,$(),$(false),$(null)等
      5     if ( !selector ) {
      6         return this;
      7     }
      8 
      9     // 处理HTML字符串,如<div></div>
     10     if ( typeof selector === "string" ) {
     11         if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
     12             // 认为标签从<开始>结束,且长度大于3
     13             match = [ null, selector, null ];
     14 
     15         } else {
     16             match = rquickExpr.exec( selector );      //rquickExpr = /^(?:s*(<[wW]+>)[^>]*|#([w-]*))$/
     17         }
     18 
     19         // 确认是HTML字符串而不是#id
     20         if ( match && (match[1] || !context) ) {
     21 
     22             // 将HTML字符串转化为合适的DOM
     23             if ( match[1] ) {
     24                 context = context instanceof jQuery ? context[0] : context;
     25 
     26                 // 得到上下文环境context
     27                 // 用parseHTML将字符串转化为DOM,然后将之合并到this中,merge适合于数组的合并
     28                 jQuery.merge( this, jQuery.parseHTML(
     29                     match[1],
     30                     context && context.nodeType ? context.ownerDocument || context : document,
     31                     true
     32                 ) );
     33 
     34                 // 处理$(html,props),这段函数将对上面生成的DOM加入prop中的属性,如class,style。rsingleTag = (/^<(w+)s*/?>(?:</1>|)$/)
     35                 if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
     36                     for ( match in context ) {
     37                         // 若是事件函数,则调用this中相应的添加事件函数的方法,将函数绑定
     38                         if ( jQuery.isFunction( this[ match ] ) ) {
     39                             this[ match ]( context[ match ] );
     40 
     41                         // 设置属性值
     42                         } else {
     43                             this.attr( match, context[ match ] );
     44                         }
     45                     }
     46                 }
     47 
     48                 return this;
     49 
     50             // 处理$(#id)的情况
     51             } else {
     52                 elem = document.getElementById( match[2] );
     53 
     54                 // 判断是否有parentnode
     55                 // 因为在某些浏览器下getElementById会返回已删除的节点
     56                 if ( elem && elem.parentNode ) {
     57                     // IE和Opera下面的特殊情况
     58                     // 会返回name的情况
     59                     if ( elem.id !== match[2] ) {
     60                         return rootjQuery.find( selector );
     61                     }
     62 
     63                     // 正常的浏览器下就直接放入到this里就好了
     64                     this.length = 1;
     65                     this[0] = elem;
     66                 }
     67 
     68                 this.context = document;
     69                 this.selector = selector;
     70                 return this;
     71             }
     72 
     73         // 处理$(expr)或者$(expr,$(..)),其中rootjQuery返回的是$(document)
     74         } else if ( !context || context.jquery ) {
     75             return ( context || rootjQuery ).find( selector );
     76 
     77         // 处理$(expr,context),注意这里的context并不是jQuery对象
     78         // 其实这段函数的原理就是jQuery(context).find(selector),因为this.constructor指向的就是jQuery
     79         } else {
     80             return this.constructor( context ).find( selector );
     81         }
     82 
     83     // HANDLE: $(DOMElement)就是在这里处理的
     84     } else if ( selector.nodeType ) {
     85         this.context = this[0] = selector;
     86         this.length = 1;
     87         return this;
     88 
     89     // 处理$(function)
     90     // 即在document ready时调用
     91     } else if ( jQuery.isFunction( selector ) ) {
     92         return typeof rootjQuery.ready !== "undefined" ?
     93             rootjQuery.ready( selector ) :
     94             // 如果没有ready的话,就立刻调用
     95             selector( jQuery );
     96     }
     97 
     98     if ( selector.selector !== undefined ) {
     99         this.selector = selector.selector;
    100         this.context = selector.context;
    101     }
    102 
    103     return jQuery.makeArray( selector, this );
    104 }

     要注意的几点:

    在这段函数中间设置断点时,让其返回this,它会返回[]。然而,正常的理解应该返回的是一个对象,而不是数组。这是因为在prototype的属性中设置了一下几个值:

    length: 0,
    push:[].push,
    sort:[].sort,
    splice:[].splice

    这样看起来就像数组了,于是调试返回的时候会出现[]........

    先就这些,以后想到啥了再补。。。。。

  • 相关阅读:
    开始熟悉一下数据结构了
    首个概率dp
    十六进制转化为八进制
    蓝桥之 剪格子
    蓝桥之 颠倒的价格
    还是闲的
    也是闲的
    闲的无聊,,,
    函数进阶
    函数基础
  • 原文地址:https://www.cnblogs.com/cyITtech/p/cy-jquery1.html
Copyright © 2011-2022 走看看