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*(<[\w\W]+>)[^>]*|#([\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
这样看起来就像数组了,于是调试返回的时候会出现[]........
先就这些,以后想到啥了再补。。。。。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。