码迷,mamicode.com
首页 > Web开发 > 详细

jQuery源码研究分析学习笔记-回调函数(11)

时间:2016-08-08 12:57:23      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

// 工具函数,将字符串格式的标记转换为对象格式,并把转换结果缓存起来
function createFlags( flags ) {

    //初始化返回值object和flagsCache[flags]为空对象,同时指向了同一个空对象,当变量object添加属性时也是在为flagsCache[flags]添加属性,不需要要再写一行代码把变量object放入缓存对象flagsCache中了
    var object = flagsCache[ flags ] = {},
        i, length;
    flags = flags.split( /\s+/ ); //用空白符把标记字符串分割为数组
    //遍历数组,为返回值object添加单个标记,属性值为true,最后返回对象
    for ( i = 0, length = flags.length; i < length; i++ ) {
        object[ flags[i] ] = true;
    }
    return object;
}

jQuery.Callbacks = function( flags ) {

    // 解析字符串标记为flags为对象,先从缓存对象flagsCache中获取标记字符串flags对应的标记对象,如果没有找到,在调用工具函数createFlags(flags)将标记字符串flags解析为标记对象,并放入寒碜对象flagsCache中
    flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};

    var // 声明局部变量,通过闭包机制引用
        list = [],//存放回调函数的数组

        //在可重复触发、正在执行的列表上,重复触发时,将上下文和参数放入数组stack中
        stack = [],

        memory,
        // 
        fired,
        // 回调函数列表是否正在执行中
        firing,
        // 待执行的第一个回调函数的下标
        firingStart,
        // End of the loop when firing
        firingLength,
        // Index of currently firing callback (modified by remove if needed)
        firingIndex,
        // 添加回调函数的工具函数
        add = function( args ) {
            var i,
                length,
                elem,
                type,
                actual;
                //遍历参数args,把回调函数逐个添加到数组list中,
            for ( i = 0, length = args.length; i < length; i++ ) {
                elem = args[ i ];
                type = jQuery.type( elem );
                //判断args[i]类型,如果是数组,则迭代调用规矩函数add(args)把数组中的回调函数添加到数组list中,
                if ( type === "array" ) {

                    add( elem );
                } else if ( type === "function" ) {
                    // 如果是函数且不是unique模式,或者是unique模式但未添加过,才会添加args[i]到数组中list中
                    if ( !flags.unique || !self.has( elem ) ) {
                        list.push( elem );
                    }
                }
            }
        },
        // 触发回调函数的工具函数,使用上下文context和参数args调用数组list中的回调函数,该回调函数通过闭包机制引用数组list
        //参数context用于指定回调函数执行时的上下文,即关键字this所引用的对象,参数args用于指定调用回调函数时传入的参数
        fire = function( context, args ) {
            args = args || [];
            //若当前回调函数列表不是memory模式,则变量memory则被赋值为true,间接地表示当前回调函数列表已经被触发过
            memory = !flags.memory || [ context, args ];
            fired = true;
            firing = true;
            firingIndex = firingStart || 0;
            firingStart = 0;
            firingLength = list.length;
            for ( ; list && firingIndex < firingLength; firingIndex++ ) {
                //执行回调函数list[ firingIndex ],如果返回值是false,且当前回调函数列表是stopOnFalse模式,则变量memory被赋值为true,并停止执行后续的其他回调函数,
                if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
                    memory = true; // Mark as halted
                    break;
                }
            }
            firing = false;
            if ( list ) {
            //如果不是once模式,即可以多次触发回调函数列表,则从变量stack中弹出存放的下文和参数,再次执行整个回调函数列表,直到stack为空
                if ( !flags.once ) {
                    if ( stack && stack.length ) {
                        memory = stack.shift();
                        self.fireWith( memory[ 0 ], memory[ 1 ] );
                    }
                } else if ( memory === true ) {

                    self.disable();
                } else {
                    list = [];
                }
            }
        },
        // 回调函数列表,方法jQuery.Callbacks(flags)的返回值
        self = {
            // 添加回调函数
            add: function() {
                if ( list ) {
                    //先备份数组list长度
                    var length = list.length;
                    add( arguments );

                    // 如果回调函数正在执行,修正结束下标firingLength,使得新添加的回调函数也得以执行
                    if ( firing ) {
                        firingLength = list.length;


                    // 
                    } else if ( memory && memory !== true ) {
                        firingStart = length;
                        fire( memory[ 0 ], memory[ 1 ] );
                    }
                }
                return this;
            },
            // 移除回调函数,从回调函数列表中移除一个或一组回调函数,移除前修正结束下标firingLength和当前下班firingIndex
            remove: function() {
                if ( list ) {
                    var args = arguments,
                        argIndex = 0,
                        argLength = args.length;
                    //遍历待移除的回调函数数组,在循环体内嵌套遍历已有的回调函数数组,
                    for ( ; argIndex < argLength ; argIndex++ ) {
                        for ( var i = 0; i < list.length; i++ ) {
                        //如果检查到某个待移除回调函数与某个已有的回调函数完全相等,则从已有的回调函数数组中移除它
                            if ( args[ argIndex ] === list[ i ] ) {
                                // 回调函数是否在列表中
                                if ( firing ) {

        //如果回调函数列表正在执行                          if ( i <= firingLength ) {
            //在移除前使用结束下标firingLength减1                          firingLength--;
            //如果待移除函数的下标小于正在执行回调函数的下标firingIndex,即待移除的回调函数已经执行,则修正firingIndex减1,以确保不会漏执行回调函数                            if ( i <= firingIndex ) {
                                            firingIndex--;
                                        }
                                    }
                                }
                                // 调用数组原型方法splice(),从匹配下标处开始移除1个元素,循环变量i自减一,修正为下一个回调函数的下标
                                list.splice( i--, 1 );
                                /
                                // 在unique模式下,数组list中不会有重复的回调函数,可以直接退出内层遍历,针对unique模式做的优化
                                if ( flags.unique ) {
                                    break;
                                }
                            }
                        }
                    }
                }
                return this;
            },
            // 回调函数是都在列表中
            has: function( fn ) {
                if ( list ) {
                    var i = 0,
                        length = list.length;
                    for ( ; i < length; i++ ) {
                        if ( fn === list[ i ] ) {
                            return true;
                        }
                    }
                }
                return false;
            },
            // 清空列表
            empty: function() {
                list = [];
                return this;
            },
            // 禁用列表
            disable: function() {
                list = stack = memory = undefined;
                return this;
            },
            // 是否已禁用列表
            disabled: function() {
                return !list;
            },
            // 锁定列表
            lock: function() {
                stack = undefined;
                if ( !memory || memory === true ) {
                    self.disable();
                }
                return this;
            },
            // 是否已错定列表
            locked: function() {
                return !stack;
            },
            // 使用指定的上下文和参数调用回调函数
            fireWith: function( context, args ) {
                if ( stack ) {
                    if ( firing ) {
                        if ( !flags.once ) {
                            stack.push( [ context, args ] );
                        }
                    } else if ( !( flags.once && memory ) ) {
                        fire( context, args );
                    }
                }
                return this;
            },
            // 使用指定的参数调用回调函数,上下文为self 
            fire: function() {
                self.fireWith( this, arguments );
                return this;
            },
            // 回调函数列表是否至少执行过一次
            fired: function() {
                return !!fired;
            }
        };

    return self;
};

jQuery源码研究分析学习笔记-回调函数(11)

标签:

原文地址:http://blog.csdn.net/lfcss/article/details/52148830

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!