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

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

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

  • 相关阅读:
    java中的 equals 与 ==
    String类的内存分配
    SVN用命令行更换本地副本IP地址
    npoi 设置单元格格式
    net core 微服务框架 Viper 调用链路追踪
    打不死的小强 .net core 微服务 快速开发框架 Viper 限流
    net core 微服务 快速开发框架 Viper 初体验20201017
    Anno 框架 增加缓存、限流策略、事件总线、支持 thrift grpc 作为底层传输
    net core 微服务 快速开发框架
    Viper 微服务框架 编写一个hello world 插件02
  • 原文地址:https://www.cnblogs.com/cyITtech/p/cy-jquery1.html
Copyright © 2011-2022 走看看