jQuery源码分析之Callbacks详解(8)

在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;
            }
        }();

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgfzyd.html