本文章为 0.9 版本,将会在稍后润色更新。本文使用的 jQuery 版本为 3.4.0

我们知道使用 $ 操作符时,可以往里面塞很多类型的参数,字符串,对象,函数...,jQuery 会根据不同的参数类型,让我们执行不同的操作。这其实就是“函数重载”的价值所在:它暴露出一个简洁的接口给用户,允许用户在使用这个接口时,通过参数类型控制函数的行为方式,是一种对用户非常友好的设计。

那么 jQuery 在 $ 这里的函数重载是怎样实现的呢?这篇文章我们只关心其中的一个细枝末节,传入一个函数时,jQuery 会怎么做:

首先我们看这里,jQuery 首先会判断传入的 selector 是不是一个函数,这里使用的是包装后的 isFunction 函数,它基本等同于 typeof 判断:

if (isFunction(selector)) {
return root.ready !== undefined ?
root.ready(selector) : // Execute immediately if ready is not present
selector(jQuery);
}

如果判断是一个函数,jQuery 会去判断 root.ready 的值,这里 root 是什么呢?看下面的代码:

// Method init() accepts an alternate rootjQuery
// so migrate can support jQuery.sub (gh-2101)
root = root || rootjQuery; rootjQuery = jQuery(document);

一般情况下,rootjQuery(document) 的返回值,这里就有点绕了,因为我们本来是要解决“选择器是函数的时候,jQuery 会怎么做”的问题,现在我们先要解决“选择器是对象的时候,jQuery 会怎么做”。在源码里 jQuery 是这样处理的:

return jQuery.makeArray(selector, this);

我们越来越深入了,现在我们要解决 jQuery.makeArray 这个方法在做什么的问题,这部分的代码在这里:

makeArray: function (arr, results) {
var ret = results || []; if (arr != null) {
if (isArrayLike(Object(arr))) {
jQuery.merge(ret,
typeof arr === "string" ?
[arr] : arr
);
} else {
push.call(ret, arr);
}
} return ret;
},

可以简单理解为,jQuery 会把一个对象传入到它的数组中。

所以到目前为止,我们大概弄懂了 root 到底是个什么东西,简单来说,是一个数组,并且第一个元素是 document 对象。我们继续,接下来,我们想知道的实际上是 root.ready 是什么,当我们回顾一下最初的代码就能知道,jQuery 处理函数的逻辑就是判断 root.ready 的值,如果该值为真值,就调用 root.ready 方法,并把我们的函数当做参数传进去,如果为假值,则直接调用这个函数,把我们的 jQuery 对象当做参数传进去。

对不起,接下来的重头戏我将会在日后补上了,这次我先描述一个大概,让我们看看和 root.ready 有关的源码:

// The deferred used on DOM ready
var readyList = jQuery.Deferred(); jQuery.fn.ready = function (fn) { readyList
.then(fn) // Wrap jQuery.readyException in a function so that the lookup
// happens at the time of error handling instead of callback
// registration.
.catch(function (error) {
jQuery.readyException(error);
}); return this;
}; jQuery.extend({ // Is the DOM ready to be used? Set to true once it occurs.
isReady: false, // A counter to track how many items to wait for before
// the ready event fires. See #6781
readyWait: 1, // Handle when the DOM is ready
ready: function (wait) { // Abort if there are pending holds or we're already ready
if (wait === true ? --jQuery.readyWait : jQuery.isReady) {
return;
} // Remember that the DOM is ready
jQuery.isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be
if (wait !== true && --jQuery.readyWait > 0) {
return;
} // If there are functions bound, to execute
readyList.resolveWith(document, [jQuery]);
}
}); // ===> readyList
var readyList = jQuery.Deferred();

其实注释里也写的很清晰了,jQuery.ready 将会在 DOM 加载完毕后,调用传入的参数,但是就是这样一个简单地功能,jQuery 采用了 jQuery.Deferred() 方法去实现,这个方法到底做了什么呢?请看我(可能的)下一篇文章:)

总结一下,如果给 jQuery 传入一个函数类型的参数会发生什么?不完全准确的回答是,它会等 DOM 加载完毕后被调用。具体来说,是等待 doument 对象上的 DOMContentLoaded 事件被触发。

下面是无声的证据:

        jQuery.ready.then = readyList.then;

	// The ready event handler and self cleanup method
function completed() {
document.removeEventListener("DOMContentLoaded", completed);
window.removeEventListener("load", completed);
jQuery.ready();
} // Catch cases where $(document).ready() is called
// after the browser event has already occurred.
// Support: IE <=9 - 10 only
// Older IE sometimes signals "interactive" too soon
if (document.readyState === "complete" ||
(document.readyState !== "loading" && !document.documentElement.doScroll)) { // Handle it asynchronously to allow scripts the opportunity to delay ready
window.setTimeout(jQuery.ready); } else { // Use the handy event callback
document.addEventListener("DOMContentLoaded", completed); // A fallback to window.onload, that will always work
window.addEventListener("load", completed);
}

jQuery 源码分析:当 selector 传来一个函数时,怎么进行处理?的更多相关文章

  1. [转] jQuery源码分析-如何做jQuery源码分析

    jQuery源码分析系列(持续更新) jQuery的源码有些晦涩难懂,本文分享一些我看源码的方法,每一个模块我基本按照这样的顺序去学习. 当我读到难度的书或者源码时,会和<如何阅读一本书> ...

  2. jQuery 源码分析 8: 回头看jQuery的构造器(jQuery.fn,jQury.prototype,jQuery.fn.init.prototype的分析)

    在第一篇jQuery源码分析中,简单分析了jQuery对象的构造过程,里面提到了jQuery.fn.jQuery.prototype.jQuery.fn.init.prototype的关系. 从代码中 ...

  3. jquery源码分析之一前言篇

    1.问:jquery源码分析的版本是什么? 答:v3.2.1 2.问:为什么要分析jquery源码? 答:javascript是一切js框架的基础,jquery.es6.vue.angular.rea ...

  4. jQuery源码分析-each函数

    本文部分截取自且行且思 jQuery.each方法用于遍历一个数组或对象,并对当前遍历的元素进行处理,在jQuery使用的频率非常大,下面就这个函数做了详细讲解: 复制代码代码 /*! * jQuer ...

  5. jQuery源码分析系列

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...

  6. [转]jQuery源码分析系列

    文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...

  7. jQuery源码分析系列(转载来源Aaron.)

    声明:非本文原创文章,转载来源原文链接Aaron. 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAa ...

  8. jQuery源码分析系列——来自Aaron

    jQuery源码分析系列——来自Aaron 转载地址:http://www.cnblogs.com/aaronjs/p/3279314.html 版本截止到2013.8.24 jQuery官方发布最新 ...

  9. 原生JS研究:学习jquery源码,收集整理常用JS函数

    原生JS研究:学习jquery源码,收集整理常用JS函数: 1. JS获取原生class(getElementsByClass) 转自:http://blog.csdn.net/kongjiea/ar ...

随机推荐

  1. python的几个注意事项

    ,==============坑======= 1.可变类型的值不要作为函数参数默认值,应该是不可变的对象,如None,True,False,数字或字符串 2.小心+= a = range(10) b ...

  2. java动态加载

    先贴个笔记,后续用得着再深究. package test; import java.io.File; import java.io.IOException; import java.lang.refl ...

  3. HTTP 协议详解(转载)

    原文: http://kb.cnblogs.com/page/130970/#httpmeessagestructe HTTP协议详解 当今web程序的开发技术真是百家争鸣,ASP.NET, PHP, ...

  4. IO流(5)判断功能

    判断功能: * public boolean isDirectory():判断是否是目录 * public boolean isFile():判断是否是文件 * public boolean exis ...

  5. CDN工作过程(第二种版本)

    作者:代希刚链接:https://www.zhihu.com/question/36514327/answer/121026637来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...

  6. mysql 权限管理 针对某个库 某张表 授权 tables_priv表

    精确到表级别 针对db1的t3表 授予select权限 mysql> grant select on db1.t3 to 'mike'@'localhost'; Query OK, rows a ...

  7. PAT Spell It Right [非常简单]

    1005 Spell It Right (20)(20 分) Given a non-negative integer N, your task is to compute the sum of al ...

  8. 机器学习理论基础学习17---贝叶斯线性回归(Bayesian Linear Regression)

    本文顺序 一.回忆线性回归 线性回归用最小二乘法,转换为极大似然估计求解参数W,但这很容易导致过拟合,由此引入了带正则化的最小二乘法(可证明等价于最大后验概率) 二.什么是贝叶斯回归? 基于上面的讨论 ...

  9. 7.10 Models -- Handling Metadata(处理元数据)

    1. 随着从store中返回的records,你可能需要处理一些元数据.Metadata是伴随着特定model或者type的一种数据,而不是record. 2. 分页是使用元数据的一个常见的例子.想象 ...

  10. Matlab中图像处理实例:灰度变换,空域滤波,频域滤波,傅里叶变换的实现

    http://blog.sciencenet.cn/blog-95484-803140.html % %图像灰度变换 % f = imread('E:\2013第一学期课程\媒体计算\实验一\Img\ ...