自己动手实现 jQuery Callbacks 完整功能
上次利用中午的时间实现了部分功能的jQuery Callbacks类 , 具体可以参考上一篇 自己动手实现 jQuery Callbacks ,现在利用快下班的时间实现了其余的全部功能 :callbacks.disable , callbacks.disabled, callbacks.fired,callbacks.fireWith, callbacks.lock, callbacks.locked ,然后重构了下代码结构, 将实现放入了匿名函数内, 然后通过工厂方法 window.callbacks 返回实例,以免每次使用必须 new .
具体代码如下, 有兴趣和时间的可以对照jQuery版本的Callbacks对比下 :
( function ( window, undefined ) { // Simulate jQuery.Callbacks object function Callbacks( options ) { var ops = { once: false, memory: false, unique: false, stopOnFalse: false }, ar = [], lastArgs = null, firedTimes = 0, _disabled = false, _locked = false; if ( typeof options === 'string' && options.trim() !== '' ) { var opsArray = options.split( /\s+/ ); for ( var i = 0; i < options.length; i++ ) { if ( opsArray[i] === 'once' ) ops.once = true; else if ( opsArray[i] === 'memory' ) ops.memory = true; else if ( opsArray[i] === 'unique' ) ops.unique = true; else if ( opsArray[i] === 'stopOnFalse' ) ops.stopOnFalse = true; } } function hasName( name ) { var h = false; if ( typeof name === 'string' && name !== null && name.trim() !== '' && ar.length > 0 ) { for ( var i = 0; i < ar.length; i++ ) { if ( ar[i].name === name ) { h = true; break; } } } return h; } // add a function this.add = function ( fn ) { if ( typeof fn === 'function' ) { if ( ops.unique ) { // check whether it had been added before if ( fn.name !== '' && hasName( fn.name ) ) { return this; } } ar.push( fn ); if ( ops.memory ) { // after added , call it immediately fn.call( this, lastArgs ); } } return this; }; // remove a function this.remove = function ( fn ) { if ( typeof ( fn ) === 'function' && fn.name !== '' && ar.length > 0 ) { for ( var i = 0; i < ar.length; i++ ) { if ( ar[i].name === fn.name ) { ar.splice( i, 1 ); } } } return this; }; // remove all functions this.empty = function () { ar.length = 0; return this; }; // check whether it includes a specific function this.has = function ( fn ) { var f = false; if ( typeof ( fn ) === 'function' && fn.name !== '' && ar.length > 0 ) { for ( var i = 0; i < ar.length; i++ ) { if ( ar[i].name === fn.name ) { f = true; break; } } } return f; }; this.disable = function () { _disabled = true; return this; }; this.disabled = function () { return _disabled; }; this.fired = function () { return firedTimes > 0; }; function _fire( context, args ) { if ( _disabled || ops.once && firedTimes > 0 || _locked ) { return; } if ( ar.length > 0 ) { var r; for ( var i = 0; i < ar.length; i++ ) { r = ar[i].call( context, args ); if ( ops.stopOnFalse && r === false ) { break; } } } firedTimes++; if ( ops.memory ) { lastArgs = args; } }; this.fireWith = function ( context, args ) { context = context || this; _fire( context, args ); return this; }; this.fire = function ( args ) { _fire( this, args ); return this; }; this.lock = function () { _locked = true; return this; }; this.locked = function () { return _locked; }; }; // exposed to global as a factory method window.callbacks = function ( options ) { return new Callbacks( options ); }; } )( window );
为了测试fireWith ,增加了一个新的测试函数fn4
var fn1 = function ( v ) { console.log( 'fn1 ' + ( v || '' ) ); }; var fn2 = function ( v ) { console.log( 'fn2 ' + ( v || '' ) ); return false; }; function fn3( v ) { console.log( 'fn3 ' + ( v || '' ) ); }; function fn4( args ) { console.log( 'context is ' + this.toString() + ' argument is ' + args ); };
1.测试fireWith
var cb=callbacks() ;
cb.add(fn4)
cb.fireWith() // context is [object Object] argument is undefined
cb.fireWith(1) // context is 1 argument is undefined
cb.fireWith(window,1) // context is [object Window] argument is 1
2. 测试 lock
var cb=callbacks('memory');
cb.add(fn1) ; // fn1
cb.fire(1) // fn1 1
cb.add(fn2) // fn2 1
cb.lock() // 没有输出
cb.locked() // true
cb.fire(2) // 没有输出
3. 测试disable
var cb=callbacks();
cb.add(fn1) ;
cb.fire(1) // fn1 1
cb.disable() ;
cb.disabled() // true
cb.fire(1) // 没有输出
通过以上重复造轮子, 对jQuery.Callbacks了解了也更多了一些 。接下来再造造jQuery其他方面的轮子,以学习和强化js 吧。。