jQuery构造函数init参数分析(三)
分析完了字符串情况剩下的就不多了。
5.参数selector是函数
这个就是很容易想到了,首先说一下dom加载。我们通常在head里面写脚本的时候需要等待文档加载在进行处理,js是这么写的
1 window.onload=function(){ 2 your code... 3 }
但是这样是需要等待所有资源都加载完毕才会执行,如果页面有很多图片的话就会加载的很慢。dom2级呢有一个加载完成事件DOMContentLoad比较好用,这个事件是会在html文档结构加载完毕触发。比如说这个页面有10个img元素,只要获取到这些元素而不会在意是否图片被加载进来这样就很好地提高了js加载速度,用法如下:
1 addEventListener("DOMContentLoad", function () { 2 your code 3 }, false);
遗憾的是ie低版本浏览器并不支持这种写法,首先ie低版本没有addEventListener这个绑定事件的方法,倒是有一个相似方法addEvent但是由于存在很多问题往往不被使用,再者ie低版本没有DOMContentLoad事件。那么针对ie低版本(ie9一下)呢通常用doScroll结合onreadystatechange方法检测。具体可以参考http://www.iefans.net/ie-mofang-domcontentloaded/
说完了回到jQuery,我们使用jQuery时就不用考虑浏览器兼容问题了直接:
1 $(function(){ 2 yourcode... 3 }) 4 5 //或者 6 7 $(document).ready(function(){ 8 yourcode... 9 })
第一种就是我们要讲的情况selector是一个函数,其实jQuery会调ready方法,源码如下:
1 // HANDLE: $(function) 2 // Shortcut for document ready 3 } else if ( jQuery.isFunction( selector ) ) { 4 return rootjQuery.ready( selector ); 5 }
rootjQuery之前也已经说过啦就是$(document),最终还是执行的ready方法这就是为什么dom加载的两种写法都可以,关于readdy方法也是会用到之前分析的DOMContentLoad,doScroll,onreadystatechange等只不过会更复杂写以后学到dom加载模块在慢慢分析吧。
6.selector是jQuery对象或者特殊对象
这个种情况应该不多没有人喜欢这样$($(document))写吧,但是如果非要有人这样写jQuery也支持
1 if ( selector.selector !== undefined ) { 2 this.selector = selector.selector; 3 this.context = selector.context; 4 }
如果selector存在selector属性说明就可能是jquery对象,为什么说可能是呢,看下面的例子就明白了
1 console.log($({selector:1}));
当我这样写的时候是不是selector(此时是对象{selector:1})的selector属性存在啊而且最后也会生成结果
[Object, selector: 1, context: undefined, constructor: function, init: function, jquery: "1.7.1"…] 0: Object context: undefined length: 1 selector: 1 __proto__: jQuery[0]
这个是对原书作者的修正,并不是只有jQuery对象才在这里处理
如果前面说的所有情况都不符合那么jQuery还有最后一招
return jQuery.makeArray( selector, this );
makeArray方法将类数组对象转换为数组对象。但是在代码内部还有更艰巨的任务就是把一些数组、类数组普通对象等不是jQuery的形式的转换成jQuery形式。这个方法在以后详细分析。到了这里jQuery构造函数init的参数就分析完了大类有7个细分呢有12个分类。用原书一张图总结一下吧
下面是整个init函数1.7.1的源码
1 init: function( selector, context, rootjQuery ) { 2 var match, elem, ret, doc; 3 4 // Handle $(""), $(null), or $(undefined) 5 if ( !selector ) { 6 return this; 7 } 8 9 // Handle $(DOMElement) 10 if ( selector.nodeType ) { 11 this.context = this[0] = selector; 12 this.length = 1; 13 return this; 14 } 15 16 // The body element only exists once, optimize finding it 17 if ( selector === "body" && !context && document.body ) { 18 this.context = document; 19 this[0] = document.body; 20 this.selector = selector; 21 this.length = 1; 22 return this; 23 } 24 25 // Handle HTML strings 26 if ( typeof selector === "string" ) { 27 // Are we dealing with HTML string or an ID? 28 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { 29 // Assume that strings that start and end with <> are HTML and skip the regex check 30 match = [ null, selector, null ]; 31 32 } else { 33 match = quickExpr.exec( selector ); 34 } 35 36 // Verify a match, and that no context was specified for #id 37 if ( match && (match[1] || !context) ) { 38 39 // HANDLE: $(html) -> $(array) 40 if ( match[1] ) { 41 context = context instanceof jQuery ? context[0] : context; 42 doc = ( context ? context.ownerDocument || context : document ); 43 44 // If a single string is passed in and it's a single tag 45 // just do a createElement and skip the rest 46 ret = rsingleTag.exec( selector ); 47 48 if ( ret ) { 49 if ( jQuery.isPlainObject( context ) ) { 50 selector = [ document.createElement( ret[1] ) ]; 51 jQuery.fn.attr.call( selector, context, true ); 52 53 } else { 54 selector = [ doc.createElement( ret[1] ) ]; 55 } 56 57 } else { 58 ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); 59 selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; 60 } 61 62 return jQuery.merge( this, selector ); 63 64 // HANDLE: $("#id") 65 } else { 66 elem = document.getElementById( match[2] ); 67 68 // Check parentNode to catch when Blackberry 4.6 returns 69 // nodes that are no longer in the document #6963 70 if ( elem && elem.parentNode ) { 71 // Handle the case where IE and Opera return items 72 // by name instead of ID 73 if ( elem.id !== match[2] ) { 74 return rootjQuery.find( selector ); 75 } 76 77 // Otherwise, we inject the element directly into the jQuery object 78 this.length = 1; 79 this[0] = elem; 80 } 81 82 this.context = document; 83 this.selector = selector; 84 return this; 85 } 86 87 // HANDLE: $(expr, $(...)) 88 } else if ( !context || context.jquery ) { 89 return ( context || rootjQuery ).find( selector ); 90 91 // HANDLE: $(expr, context) 92 // (which is just equivalent to: $(context).find(expr) 93 } else { 94 return this.constructor( context ).find( selector ); 95 } 96 97 // HANDLE: $(function) 98 // Shortcut for document ready 99 } else if ( jQuery.isFunction( selector ) ) { 100 return rootjQuery.ready( selector ); 101 } 102 103 if ( selector.selector !== undefined ) { 104 this.selector = selector.selector; 105 this.context = selector.context; 106 } 107 108 return jQuery.makeArray( selector, this ); 109 },