jQuery方法源码解析--jQuery($)方法(一)
注:
1.本文分析的代码为jQuery.1.11.1版本,在官网上下载未压缩版即可
2.转载请注明出处
$( "span", this ).addClass( "bar" );
});
.data(),.prop(),.on(), .off(), .trigger() and .triggerHandler().
The use of .data() (or any method requiring .data()) on a plain object will result in a new
property on the object called jQuery{randomNumber} (eg. jQuery123456789).
$()
function,
a clone of the object is created. This new jQuery object references the same DOM elements as the initial one."class": "my-div",
on: {
touchstart: function( event ) {
// Do something}
}}).appendTo( "body" );
.addClass( "my-div" )
.on({
touchstart: function( event ) {
// Do something
}
})
.appendTo( "body" );
what is jQuery Object??
<ol>
<li></li>
<li></li>
<li></li>
<li></li>
</ol>
</body>
总结一下,jQuery对象,就是在js对象的基础上,包装了一些jQuery方法的对象,有一个英文词形容的比较贴切,就是wrap(包裹).
jQuery方法的结构
在jQuery1.11.1的源码中,搜索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这货:
var match, elem;
init.prototype = jQuery.fn;
jquery.init方法
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
// Strict HTML recognition (#11290: must start with <)
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/
console.log(rquickExpr.exec("<tag>"));
init = jQuery.fn.init = function( selector, context ) { var match, elem; //处理jQuery()形式,返回空的jQuery对象 // HANDLE: $(""), $(null), $(undefined), $(false) if ( !selector ) { return this; } // Handle HTML strings /*#源码分析 *匹配html(以<开头,以>结尾,或者是<tag>...形式,推荐写严格的html),或者是#id形式,并且确保,#id情况下,没有context */ if ( typeof selector === "string" ) { if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { /*#源码分析 *假设以<开头,以>结尾的,并且长度大于3的String都是htmlString,然后存到match中 */ // Assume that strings that start and end with <> are HTML and skip the regex check match = [ null, selector, null ]; } else { match = rquickExpr.exec( selector ); } /*#源码分析 *what is match? *我们分析过rquickExpr这个正则表达式,它有两个分组(最外面的那个分组不捕获,没算), *这样使用exec方法后,如果匹配到了,则应该返回一个长度为3,包括index和input属性的数组。 *那么match[0]是整体匹配的数组,match[1]是匹配的<tag>标签(如果有),match[2]匹配#id(如果有) *显然match[1],match[2]只能有一个被捕获 */ // Match html or make sure no context is specified for #id if ( match && (match[1] || !context) ) { //处理jQuery( html [, ownerDocument ] ),根据html生成dom元素,返回jQuery对象,就像下面的注释$(html) -> $(array) //match[1] // HANDLE: $(html) -> $(array) if ( match[1] ) { /*#源码分析 *如果context是jQuery对象,转为js原生对象. *我们说过,jQuery对象就是给js原生对象包装了了一些方法的对象,而原生对象以类数组的形式存在jQuery中, *所以context[0],就是去jQuery对象中的第一个原生对象,在这里context期待传入的就是document或者$(document) */ context = context instanceof jQuery ? context[0] : context; /*#源码分析 *这里调用了jQuery.parseHTML方法,就是把htmlString转为dom数组 *还调用了jQuery.merge(first,second),接收两个"类数组"参数, *这个方法是把第二个数组追加到第一个数组尾部,会改变第一个数组 *前面讲过,jQuery对象具有类数组结构,当前还没有操作this,它的length = 0 *所以下面这段代码,就是把htmlString转为dom数组并追加到this的尾部。 */ // scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge( this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true ) ); /*#源码分析 *处理jQuery( html, attributes )这种用法 *第一个参数必须是单标签,第二个参数是一个普通对象,类似{html:"hello world",id:"test"} *注意,这种情况下,会走上面的分支,已经把单标签转为dom并拼接到了this中了 */ // HANDLE: $(html, props) if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { for ( match in context ) { /*#源码分析 *这里的match是context的属性 *如果有match的方法,就会调用match方法 *比如{html:"hello world",id:"test"},就会调用this.html("hello world")方法 *否则按照属性处理 */ // Properties of context are called as methods if possible if ( jQuery.isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes } else { this.attr( match, context[ match ] ); } } } return this; /*#源码分析 *处理match[2]被捕获到的情况,也就是#id的情况 */ // HANDLE: $(#id) } else { elem = document.getElementById( match[2] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 // 为了兼容Blackberry 4.6中的一个bug,不但判断element,还要判断elem.parentNode if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID /*#源码分析 *早期的IE的document.getElementById()有bug,在查找元素时,会把表单的元素的name也看成是id, *这时候使用find方法来兼容,搜索一下"rootjQuery =",会发现rootjQuery = jQuery( document ); */ if ( elem.id !== match[2] ) { return rootjQuery.find( selector ); } /*#源码分析 *否则直接放到this[0]中 */ // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } /*#源码分析 *处理$(复杂选择器的情况),采用find方法处理并返回, *这里两个else的判断,就是为了确保是jQuery对象调用find方法, *如果context不是jQuery对象,使用constructor构造一个 *context.jquery-->jquery是jQuery.fn上的一个版本属性,在此用这个来判断是否是jQuery对象。 */ // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } /*#源码分析 *else selector不是String类型的 */ // HANDLE: $(DOMElement) } else if ( selector.nodeType ) { /*#源码分析 *处理$(DOMElement)形式,这个比较简单,就是加到this[0]上 */ this.context = this[0] = selector; this.length = 1; return this; // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { /*#源码分析 *$(function)形式,就是调用了$(document).ready()方法 */ return typeof rootjQuery.ready !== "undefined" ? rootjQuery.ready( selector ) : // Execute immediately if ready is not present selector( jQuery ); } /*#源码分析 *如果selector.selector !== undefined,那么selector本身可能就是一个jQuery对象,做了如下处理,为什么呢?!不知道 */ if ( selector.selector !== undefined ) { this.selector = selector.selector; this.context = selector.context; } /*#源码分析 *jQuery.makeArray(arr)是把类数组,转为纯数组形式,API是这么说的. *实际上makeArray还有第二个参数,但仅限内部使用,就是现在这种情况 *jQuery.makeArray( arr, results ) -->把调用jQuery.merge把arr数组追加到results尾部 *这里会处理jQuery( elementArray )、jQuery( object )这两种情况 */ return jQuery.makeArray( selector, this ); };
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。