在add()的时候,jQuery并没有给变量auto(memory)赋值,而是选择在coreFire()中给auto(memory)赋值,这样就保证了第一次fire()之后才会开启自动执行。
按照上面所说,coreFire()接收的参数其实是一个数组,第一个参数是上下文,第二个参数是外面传递进来的参数。同时把这个数组赋值给auto(memory),这样,变量auto(是否自动执行模式)的定义就变成了memory(记忆最后一次传递的参数)。
真是一石二鸟的神思路,神想法,不得不点赞。我定义这个为auto是因为它的本身就是一个自动执行的模型,顺便保存了最后一次fire()的参数,而jQuery定义为memory或许也是作者感叹这里的鬼斧神工吧。
至于once&auto就是把这两个代码揉合到一起而已,只需要在coreFire()里判定如果是auto模式,那么就把list重置为一个新的数组,否则直接设置为undefined即可。
源码
这份代码是自己对应jQuery手写的一份,将一些jQuery公有的函数都写了进来,并非代码片段,所以可以直接引用运行。
复制代码 代码如下:
(function (window, undefined) {
/*
* 一个回调函数工具对象,注意这个工作对象工作完成之后就会清空数组:
* 提供一组普通的API,但它有如下工作模型 -
* once - 单次执行模型:每次工作一次,后续不再工作
* auto - 自动执行模型:每添加一个回调函数,自动执行现有的回调函数集合里的所有回调函数,并将本次的参数传递给所有的回调函数
*
*/
//工具函数
var isIndexOf = Array.prototype.indexOf, //Es6
toString = Object.prototype.toString, //缓存toString方法
toSlice = Array.prototype.slice, //缓存slice方法
isFunction = (function () { //判定一个对象是否是Function
return "object" === typeof document.getElementById ?
isFunction = function (fn) {
//ie下对DOM和BOM的识别有问题
try {
return /^\s*\bfunction\b/.test("" + fn);
} catch (x) {
return false
}
} :
isFunction = function (fn) { return toString.call(fn) === '[object Function]'; };
})(),
each = function () { //循环遍历方法
//第一个参数表示要循环的数组,第二个参数是每次循环执行的函数
if (arguments.length < 2 || !isFunction(arguments[1])) return;
//为什么slice无效??
var list = toSlice.call(arguments[0]),
fn = arguments[1],
item;
while ((item = list.shift())) {//没有直接判定length,加速
// 为什么这里用call就可以,而apply就不行?
//搞定 - apply的第二个参数必须是一个array对象(没有验证array-like是否可以,而call没有这个要求)
//apply是这样描述的:如果 argArray(第二个参数) 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
fn.call(window, item);
}
},
inArray = function () { //检测数组中是否包含某项,返回该项索引
//预编译
return isIndexOf ? function (array, elem, i) {
if (array)
return isIndexOf.call(array, elem, i);
return -1;
} : function (elem, array, i) {
var len;
if (array) {
len = array.length;
i = i ? i < 0 ? Math.max(0, len + i) : i : 0;
for (; i < len; i++) {
if (i in array && array[i] === elem) {
return i;
}
}
}
return -1;
}
}();