jQuery:理解$(document).ready()的特殊写法
看书时注意到下面两条语句的功效是相同的,$(function(){alert("hello!");});
$(document).ready(function(){alert("hello!");});
这个特殊写法就是用$()代替$(document).ready(),类似于(有差异)window.onload弹出个窗口:
查看jQuery1.8.3源代码,是这样封装的:
(function( window, undefined ) {
/*...jQuery源代码全部都在这里了...*/
})( window );
下列语句把封装在内部的jQuery先赋给window.$,紧接着再赋给window.jQuery。这意味着在实际使用时window.$和window.jQuery是一回事。因为$这个符号只有1个字母,比jQuery短,所以更常用一些,但要注意到$非jQuery所独有,节约字母的代价是增加了命名冲突的风险。
// Expose jQuery to the global object
window.jQuery = window.$ = jQuery;
下面是jQuery的初始化语句(注意到此时函数并未执行):
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
}
找到jQuery.fn的定义,这是一个对象,其中有一个叫init的函数元素:
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;
// Handle $(""), $(null), $(undefined), $(false)
if ( !selector ) {
return this;
}
// Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}
/*...以下省略...*/
继续下去,init中有一段逻辑:
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
晕了晕了,rootjQuery的定义又回到了jQuery:
// All jQuery objects should point back to these
rootjQuery = jQuery(document);
有点递归的意思了,嗯,就是递归。jQuery不仅仅是一个函数,而且还是一个递归函数。
如果调用jQuery时输入的是一个函数,例如文章开头提到的:
$(function(){alert("hello!");});
那么这个函数就会走到rootjQuery那里,再回到jQuery,执行jQuery(document).ready。而$与jQuery是一回事,这样就解释了$(inputFunction)可以代替$(document).ready(inputFunction)。
现在还不想结束此文,我的问题是$(document)做了什么?嗯,还是要进入到jQuery.fn.init,确认存在nodeType属性,达到“Handle $(DOMElement)”的目的。怎么Handle呢?具体就是把输入参数(此时为document)赋值给this的context属性,然后再返回this。也就是说,$(document)执行完了返回的还是jQuery,但是情况发生了变化,具体就是context属性指向了输入参数(此时为document)。暂时还不明白绕这么大个圈子为context(上下文)属性赋值有何意义?
接下去的问题可能会是$(document).ready和window.onload的区别?提取ready函数的定义如下:
ready: function( fn ) {
// Add the callback
jQuery.ready.promise().done( fn );
return this;
},
阅读代码探究promise是有点晕啊,想到自己的iJs工具包了,打印jQuery.ready.promise()如下:
[Object] jQuery.ready.promise()
|--[function] always
|--[function] done
|--[function] fail
|--[function] pipe
|--[function] progress
|--[function] promise
|--[function] state
|--[function] then
进一步打印整理done函数代码如下(这下彻底晕了~~):
function() {
if ( list ) {
// First, we save the current length
var start = list.length;
(function add( args ) {
jQuery.each( args, function( _, arg ) {
var type = jQuery.type( arg );
if ( type === "function" ) {
if ( !options.unique || !self.has( arg ) ) { list.push( arg ); }
} else if ( arg && arg.length && type !== "string" ) {
// Inspect recursively add( arg );
}
});
})( arguments );
// Do we need to add the callbacks to the
// current firing batch?
if ( firing ) {
firingLength = list.length;
// With memory, if we're not firing then
// we should call right away
} else if ( memory ) {
firingStart = start;
fire( memory );
}
}
return this;
}
好在代码不长,看起来关键就在于fire函数了。嗯,找回一丝清醒了。在上面的done函数里面可以注意到使用了默认的arguments变量,将注入的函数push到了list数组。下面是fire函数:
fire = function( data ) {
memory = options.memory && data;
fired = true;
firingIndex = firingStart || 0;
firingStart = 0;
firingLength = list.length;
firing = true;
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
memory = false; // To prevent further calls using add
bre
补充:web前端 , JavaScript ,
- 更多JAVA疑问解答:
- java怎么在线读取ftp服务器上的文件内容
- 关于程序员的职业规划
- HTML和JSP矛盾吗?
- java小程序如何打包?
- java怎么split路径文件名?
- jsp+javaBean中Column 'ordersPrice' specified twice的错误
- Java TCP/IP Socket网络编程系列
- 大家来讨论一下我到底该用什么好?Swing 还是 JavaFX
- 关于Hibernate实体自身多对一的抓取问题
- 关于apache2+tomcat群集出现的问题
- spring 获取上下文问题
- SSH 导入导出excel 谁有这块的资料吗?
- Ext TreePanel 刷新问题
- springmvc 加载一个jsp页面执行多个方法 报404
- checkbox数组action怎么向页面传值