当前位置: 代码迷 >> Web前端 >> 躺在jquery的石榴裙上 之 jQuery.fn.init
  详细解决方案

躺在jquery的石榴裙上 之 jQuery.fn.init

热度:599   发布时间:2012-11-10 10:48:50.0
躺在jquery的石榴裙下 之 jQuery.fn.init
认识第一个比较重要的方法jQuery.fn.init
源码如下:
selector = selector || document;
if ( selector.nodeType ) {
	this[0] = selector;
	this.length = 1;
	return this;
}


selector = selector || document 暗示了如果$(),那么就相当于$(document)

selector.nodeType用来判断是否是一个domElement对象,如果是直接将本对象包装成jquery对象返回,这里要说明一点,实际jquery对象是一个伪数组或者说是一个功能异常强大的集合,你可以通过下标去访问里面的元素和length属性,但它不会像数组一样去帮你维护里面的元素,比如你将length设为空,它不会帮你将里面的元素清空,因为他是一个伪造的。

if ( typeof selector == "string" ) {
     ....
}else if ( jQuery.isFunction( selector ) )
	return jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector );

return this.setArray(jQuery.makeArray(selector));

判断是否是字符串,情况比较多,稍后讨论,先看简单的,好像也不太简单
jQuery.isFunction( selector ) 判断传进来的是否是一个函数
isFunction函数体如下:
return !!fn && typeof fn != "string" && !fn.nodeName &&
	fn.constructor != Array && /^[\s[]?function/.test( fn + "" );

!!fn强制返回boolean型,然后否定了它不是字符串,不是dom元素,不是数组,然后用一个正则进行验证,为什么要加个"^[\s[]?"让我很困惑,因为这是一个全局函数所以才判断这么多,实际上就这个逻辑关系,只用最后一个验证就行了,因为前面已经都有对应的判断了,不过这个方法还是相当具有价值的,多多品味

jQuery( document )返回是一个骨子里是document的jquery对象
[ jQuery.fn.ready ? "ready" : "load" ]如果jQuery.fn存在ready属性,返回[ready]否则返回[load],这种写法很值得借鉴,简洁高效

下面找寻load,ready方法
load : (约2420) 牵涉事件,暂时搁置一下
ready : (约2282)
jQuery.fn.ready: function(fn) {
	bindReady(); //关于事件暂时不讨论
	if (jQuery.isReady)
		fn.call(document, jQuery); 
	else
		jQuery.readyList.push(function() { 
                       return fn.call(this, jQuery); 
                  }); 
	return this;
}
jquery有一套快速的检查文档是否加载完毕的例子,这个要比传统的window.onload要快,他的实现是通过一个计时器,不停的检查,知道加载好后将jQuery.isReady属性等于true
,所以上面这段代码意思就是,如果没有加载好就将其放入readyList数组中,当前的this指向调用ready的jquery对象(即$(document)),而且这个函数还被注入了jQuery参数,所以想查看readyList里面的个数 $(function(j){alert(j.readyList.length)}),如果dom已经加载好,就会直接执行

当dom从未加载好到加载好后,会调用全局的jQuery.ready(约2304),将isReady改为true,然后遍历readyList数组,执行里面的方法,一定要把最后页面执行$()里面function这个过程想通

下一个return this.setArray(jQuery.makeArray(selector));
setArray: function(elems) {
	this.length = 0;
	Array.prototype.push.apply(this, elems); 

	return this;
}
因为是伪数组,所以记住在改变数组时要自己维护length,剩下就不解释了,属于借鸡生蛋的做法

makeArray: function(array) {
	var ret = []; 
	if (array != null) {
		var i = array.length;
		if (i == null || array.split || array.setInterval || array.call)
			ret[0] = array;
		else
			while (i)
			ret[--i] = array[i];
	} 
	return ret;
}
注意有length属性不仅仅是array,还有arguments,function,伪数组(例如jquery对象),window。i == null主要是针对没有length属性的,比如object,12,true这样的基本类型,这函数的意义就是无论什么将它构造成一个数组。作者之所以分成两个方法,是考虑到粒度的问题,这种粒度对后面的重用会大有帮组


最麻烦的:if ( typeof selector == "string" )这块
首先来看看我们已经分析了那些还剩下那些情况:

1.if ( selector.nodeType ) 处理了dom对象
2.if (jQuery.isFunction(selector)) 处理预加载函数这一块
3.this.setArray(jQuery.makeArray(selector)) 处理了数组和伪数组情况

api中提供的方法,属于字符串的一块
1) 处理选择器,如  #id,.class,:input 之类的
2) 直接构建dom,$("<div><p>Hello</p></div>")

init方法上有两个参数selector, context其中context就是规定它的寻找范围,主要是处于性能上的考虑,假设已经了解dom的结构,可以加快锁定元素的速度,默认为document

var match = quickExpr.exec(selector); 
if (match && (match[1] || !context)) { 
	if (match[1])
		selector = jQuery.clean([match[1]], context); 
	else {
		var elem = document.getElementById(match[3]); 
		if (elem) {
			if (elem.id != match[3])
				return jQuery().find(selector); 
			return jQuery(elem);
		}
		selector = [];
	} 
} else
	return jQuery(context).find(selector); 


quickExpr : "/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/"只关注两种情况,一种是直接针对构建dom的,一种是针对id选择器的,特别对id照顾是因为getElementById的速度是最快的,之所以会多出if (elem.id != match[3])这种情况是因为我们的ie老大哥在解析input这类的标签时在没有id有name的时候,会将name取代id,对于这种擅作主张的行为很不能接受,所要小心了。

jQuery.clean([match[1]], context) : 方法实现是创建一个临时的div,然后将
<(.|\s)+>添加到这个div的innerHTML上,会自动生成dom对象,然后解析这个对象,打包成数组返回。后面会详细说明

如果没有匹配结果或存在context的情况下,将执行jQuery(context).find(selector)方法通过选择器来寻找结果,这个选择器一块的知识后面会提到
1 楼 harry_2013 2010-11-26  
内容没看,不过这个标题很吸引人哦。不知道算不算标题党
  相关解决方案