二、构造jQuery对象1——jQuery.fn.init(selector, context, root)

jQuery.fn.init()负责解析参数selector和context的类型,并执行相应的逻辑,最后返回jQuery.fn.init()的实例。
支持12种类型,如下所示:
  1. selectort可以转换成false,示例:$(""), $(null), $(undefined), $(false)。
  2. selectort为DOM元素,示例:$(DOMElement)。
  3. selectort为字符串,具体为"body",示例:$('body')。
  4. selectort为字符串,具体为”单独标签“,示例:$('<div>')。
  5. selectort为字符串,具体为”复杂HTML代码“,示例:$('<div>abc</div>')。
  6. selectort为字符串,具体为”#id“,context为undefined,示例:$('#id')。
  7. selectort为字符串,具体为”选择器表达式“,context为undefined,示例:$('div p')。
  8. selectort为字符串,具体为”选择器表达式“,context为jQuery对象,示例:$('div p',$('#id'))。
  9. selectort为字符串,具体为”选择器表达式“,context为DOM元素,示例:$('div p',this)。
  10. selectort为函数,示例:$(function(){})。
  11. selectort为jQuery,示例:$($('div'))。
  12. selectort为其他任意类型的值,示例:$([123])。
// 代码行:2903——3014
var
rootjQuery, rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, // rquickExpr包含两个分组,一个匹配HTML、一个匹配ID。 init = jQuery.fn.init = function( selector, context, root ) { //参数selector可以是任意类型的值,但只有undefined、DOM元素、字符串、函数、jQuery对象、普通JavaScript对象这几种类型是有效的,其他类型的值也可以接受但没有意义。   //参数context可以不传,或传入DOM元素、jQuery对象、普通JavaScript对象之一。   //参数root用于document.getElementById()查找失败、selector是选择器表达式且未指定context、selector是函数三种情况情况。 var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) // 参数selector可以转化为false //如果传入的是:空字符串、null、undefined、false,则直接返回this。这时this是空jQuery对象,其属性length为0。 if ( !selector ) { return this; } // Method init() accepts an alternate rootjQuery // so migrate can support jQuery.sub (gh-2101) // 重置root:rootjQuery包含了document对象的jQuery对象,以此支持jquery.sub root = root || rootjQuery; // 参数selector是字符串 if ( typeof selector === "string" ) { // 如果参数selector以“<”开头以“>”结尾,且长度大于3。则“假设”这个字符串是HTML片段,跳过正则表达式检查。否则就用正则rquickExpr检查字符串是否是ID、标签、类选择器,匹配的结果放到match数组中。 if ( selector[ 0 ] === "<" && selector[ 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 { // 把selector进行匹配,如果匹配成功,match数组第一个元素是selector,第二个元素是HTML或者是undefined,第三个元素是ID或者是undefined。 match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id // 判断字符串是否是一个单独的标签 // 如果match[1]不是undefined,即参数selector是HTML代码,或者match[2]不是undefined,即参数selector是#id,并且未传入参数context。完整版的判断如下“if (match && (match[1] || match[2] && !context)) {}”,为什么省略了对match[2]的判断?因为如果match不是null且match[1]是undefined,那么此时match[2]必然不是undefined,所以对match[2]的判断可以省略。 if ( match && ( match[ 1 ] || !context ) ) { // HANDLE: $(html) -> $(array) // 判断字符串是HTML if ( match[ 1 ] ) { //修正context:“context = context instanceof jQuery ? context[0] : context;”。先判断第二个参数的类型在将context赋值成原生的节点。例如输入的是:$('li',document)或$('li',$(document))。   context = context instanceof jQuery ? context[ 0 ] : context; //判断能否向后兼容:“jQuery.merge(this, jQuery.parseHTML())”。 // jQuery.parseHTML()用于将HTML字符串解析为对应的DOM节点数组。有三个参数:htmlString,context,keepScripts。HTMLString,string类型,需要解析并转为DOM节点数组的字符串。context,element类型。指定在那个document中创建元素。默认为当前文档的document。keepscript,boolean类型,指定传入的字符串中是否包含脚本,默认为false。 // 我们传入了三个参数:"match[ 1 ],context && context.nodeType ? context.ownerDocument || context : document,true"。如果context与context的节点存在,使用context或context的owner document,否则用默认参数domcument。 // jQuery.merge()用于合并两个数组内容到第一个数组。注意这时传入的this是个json对象而不是数组,通过这种方式也能进行合并并返回jQuery想要的json格式。 jQuery.merge( this, jQuery.parseHTML( match[ 1 ], context && context.nodeType ? context.ownerDocument || context : document, true ) ); // HANDLE: $(html, props) // 解析$(HTML, props)格式 // 如果正则rsingleTag验证"match[1]"是否是一个单独的标签,且context是一个纯粹的对象条件成立。循环这个json对象,并判断json里的属性是否是jq自带的方法,如果是,则直接调用方法,否则,用jq的attr方法为这个标签加一个“match”属性。 if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { for ( match in context ) { // Properties of context are called as methods if possible if ( isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes } else { this.attr( match, context[ match ] ); } } } // 返回当前对象 return this; // HANDLE: $(#id) // 判断字符串是ID且未指定参数 } else { //使用getElementById()方法查找含有Id属性的DOM元素  elem = document.getElementById( match[ 2 ] ); //如果DOM元素存在,设置第一个元素,属性length,并返回当前对象。 if ( elem ) { // Inject the element directly into the jQuery object this[ 0 ] = elem; this.length = 1; } // 返回当前对象 return this; } } // HANDLE: $(expr, $(...)) // 判断字符串是选择器表达式 else if ( !context || context.jquery ) { // 如果没有指定上下文,则执行root.find(selector);如果指定了上下文,且上下文是jQuery对象,则执行context.find(selector); return ( context || root ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } // 如果制定了上下文,但上下文不是jQuery对象,则执行this.constructor(context).find(selector),即先创建一个包含了context的jQuery对象,然后在该对象上调用find()方法。 else { return this.constructor( context ).find( selector ); } // HANDLE: $(DOMElement) } //  如果参数selector含有属性nodeType,则认为selector是DOM元素,设置第一个元素指向该DOM元素、属性length为1,然后返回包含了改DOM元素引用的jQuery对象。:nodeType声明了文档树中节点的类型,例如,element节点的该属性值是1,text节点是3,comment是9,document是9,documentfragment节点是11。 // 参数selector是节点,设置第一个元素、属性length,并返回当前对象。 else if ( selector.nodeType ) { this[ 0 ] = selector; this.length = 1; return this; } // HANDLE: $(function) // Shortcut for document ready // 参数selector是函数 else if ( isFunction( selector ) ) { //  判断root.ready是否存在,存在则执行root.ready(selector),否则执行该方法; return root.ready !== undefined ? root.ready( selector ) : // Execute immediately if ready is not present selector( jQuery ); } // 参数selector是任意值,如果selector是数组或伪数组(如jQuery对象),则都添加到当前jQuery对象中;
  // 如果selector是JavaScript对象,则作为第一个元素放入当前jQuery对象中;
  // 如果是其他类型的值,则作为第一个元放入当前jQuery对象中。最后返回当前对象。
return jQuery.makeArray( selector, this ); }; // 通过“init.prototype = jQuery.fn;”用jQuery()原型对象覆盖了jQuery.fn.init()的原型对象。 init.prototype = jQuery.fn; // Initialize central reference
//
初始化rootjQuery
rootjQuery = jQuery( document );

 

posted @ 2019-03-18 18:23  道鼎金刚  阅读(1071)  评论(0)    收藏  举报