jquery.callbacks(源码)

<script>
		$().ready(function() {
			
		

		var optionsCache = {};

		var core_rnotwhite = /\S+/g;

		function createOptions( options ) {
			var object = optionsCache[ options ] = {};
			jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
				object[ flag ] = true;
			});
			return object;
		}

		jQuery.Callbacks = function( options, ly ) {

			// Convert options from String-formatted to Object-formatted if needed
			// (we check in cache first)
			options = typeof options === "string" ?
				( optionsCache[ options ] || createOptions( options ) ) :
				jQuery.extend( {}, options );//jQuery.extend( {}, options ) ==> 如果没有传递参数进来,或者options不是字符串的情况,如果options是对象,则options = options
				//jQuery.extend( {}, options ) ==>如果options是[],则options为{0: options}
				
			var // Last fire value (for non-forgettable lists)
				memory,
				// Flag to know if list was already fired
				fired,
				// Flag to know if list is currently firing
				firing,
				// First callback to fire (used internally by add and fireWith)
				firingStart,
				// End of the loop when firing
				firingLength,
				// Index of currently firing callback (modified by remove if needed)
				firingIndex,
				// Actual callback list
				list = [],
				// Stack of fire calls for repeatable lists
				stack = !options.once && [],//这种情况是对象参数有传once
				// Fire callbacks
				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 ) {
							/*
							*list[ firingIndex ].apply( data[ 0 ], data[ 1 ] )-->对数组下面的每一个项进行操作,
							*data[0]-->执行环境,data[1],是指Callbacks对象触发fire()时传递进来的参数
							*list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false表示,回调函数返回为false的时候
							*list = [aaa, bbb]-->list[ 0 ].apply( data[ 0 ], data[ 1 ] )-->即是调用aaa()
							*/
							memory = false; // To prevent further calls using add
							break;
						}
					}
					firing = false;//循环结束后,表示触发过程已经结束了
					if ( list ) {
						if ( stack ) {
							if ( stack.length ) {
								fire( stack.shift() );
							}
						} else if ( memory ) {//这种情况是有传递once和memory的情况
							list = [];
						} else {
							self.disable();//阻止后面的操作
						}
					}
				},
				// Actual Callbacks object
				self = {
					// Add a callback or a collection of callbacks to the list
					add: 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 ) {
								/*
								*第一次调用add的时候,创建Callbacks对象的时候不管是否有memory这个参数,这个时候if里面的memory都是false
								*只有在调用过一次fire()方法后,并且创建Callbacks对象的时候有memory这个参数,这时候memory才是true,相当于下面的用法的时候,触发了这一块
								*var cb = $.Callbacks('memory'); cb.add(params); cb.fire(); cb.add(params);-->第二个add方法会触发一次fire()
								*/
								firingStart = start;
								fire( memory );
							}
						}
						return this;
					},
					// Remove a callback from the list
					remove: function() {
						if ( list ) {
							jQuery.each( arguments, function( _, arg ) {
								var index;
								while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
									list.splice( index, 1 );
									// Handle firing indexes
									if ( firing ) {
										if ( index <= firingLength ) {
											firingLength--;
										}
										if ( index <= firingIndex ) {
											firingIndex--;
										}
									}
								}
							});
						}
						return this;
					},
					// Check if a given callback is in the list.
					// If no argument is given, return whether or not list has callbacks attached.
					has: function( fn ) {
						return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
					},
					// Remove all callbacks from the list
					empty: function() {
						list = [];
						firingLength = 0;
						return this;
					},
					// Have the list do nothing anymore
					disable: function() {
						list = stack = memory = undefined;//禁止所有的操作
						return this;
					},
					// Is it disabled?
					disabled: function() {
						return !list;
					},
					// Lock the list in its current state
					lock: function() {
						stack = undefined;//只是锁住数组
						if ( !memory ) {
							self.disable();
						}
						return this;
					},
					// Is it locked?
					locked: function() {
						return !stack;
					},
					// Call all callbacks with the given context and arguments
					fireWith: function( context, args ) {//context: 作用域,args:参数
						if ( list && ( !fired || stack ) ) {
							/*
							*第一次调用的时候,fired为false,!false为true,那么第一次调用的时候( !fired || stack )的值就是true
							*/
							args = args || [];
							args = [ context, args.slice ? args.slice() : args ];//将传进来的参数整成数组,好传递给fire()
							if ( firing ) {
								stack.push( args );
							} else {
								fire( args );//这时候传递给fire的args包括了具体的作用域和参数
							}
						}
						return this;
					},
					// Call all the callbacks with the given arguments
					fire: function() {
						self.fireWith( this, arguments );
						return this;
					},
					// To know if the callbacks have already been called at least once
					fired: function() {
						return !!fired;//判断是否有调用过,只要调用过一次fire()方法,都会返回true;一般函数名以ed结束,可以用来表示状态
					}
				};

				return self;
		};

		/*
			通过这几个实验,可以看出,JS的||并不是单纯的返回一个布尔类型。

			大家都知道js的布尔类型判定是

			对象是true,非零是true,非空字符串是true

			其余的都是false

			由此得出

			逻辑或 ||  : var a = 表达式1 || 表达式2

			      表达式1    表达式2    a取值

			        1          0      表达式1结果值

			        1        1      表达式1结果值

			        0        1      表达式2结果值

			        0        0      表达式2结果值

			

			逻辑与 &&  : var a = 表达式1 && 表达式2

			      表达式1    表达式2    a取值

			        1          0      表达式2结果值

			        1        1      表达式2结果值

			        0        1      表达式1结果值

			        0        0      表达式1结果值

			主要原因是因为短路,逻辑或 || 在前面有一个ture的时候则不看后面直接停止,逻辑与&&同理。
					
		*/

	});

源码中stack是指堆栈:比如下面这种情况:
var bBtn = true;
    
function aaa(){
	alert(1);
	
	if(bBtn){//如果没有这个bBtn开关控制,直接在alert(1)之后执行cb.fire(),那么程序将进入死循环
		cb.fire();//这种情况下,会再向stack内push函数,让要执行的函数进入队列等待执行
		bBtn = false;
	}
	
}

function bbb(){
	alert(2);
}

var cb = $.Callbacks();

cb.add( aaa );
cb.add( bbb );

cb.fire();
	</script>

猜你喜欢

转载自blog.csdn.net/rose999ying/article/details/86532874