自己动手实现jQueryCallbacks完整功能代码详解-创新互联

最近大量的用到jQuery Callbacks 对象,jQuery库中的$.ajax()和$.Deferred() 对象也是基于这个对象实现,下面我们也模拟实现jQuery Callbacks 对象的部分功能

用法和$.Callbacks完全一致 , 但是只是实现了add , remove , fire , empty, has和带参数的构造函数功能,  $.Callbacks 还有disable,disabled, fireWith , fired , lock, locked 方法

代码如下:

复制代码 代码如下:

String.prototype.trim = function ()
    {
      return this.replace( /^\s+|\s+$/g, '' );
    };

    // Simulate jQuery.Callbacks object
    function MyCallbacks( options )
    {
      var ops = { once: false, memory: false, unique: false, stopOnFalse: 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;
        }
      }

      var ar = [];
      var lastArgs = null;
      var firedTimes = 0;

      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;
      };

      // invoke funtions it includes one by one
      this.fire = function ( args )
      {
        if ( ops.once && firedTimes > 0 )
        {
          return this;
        }

        if ( ar.length > 0 )
        {
          var r;

          for ( var i = 0; i < ar.length; i++ )
          {
            r = ar[i].call( this, args );

            if ( ops.stopOnFalse && r === false )
            {
              break;
            }
          }
        }

        firedTimes++;

        if ( ops.memory )
        {
          lastArgs = args;
        }

        return this;
      };
    };

测试函数如下:(注意fn1 fn2是匿名函数, fn2返回false , fn3是有“名”函数)

复制代码 代码如下:

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 || '' ) );
    };

1 . 测试add & fire

var cb=new MyCallbacks();

cb.add(fn1)

cb.add(fn2)

cb.add(fn3)

cb.fire('hello')

输出:

fn1 hello
fn2 hello
fn3 hello

2.测试remove
var cb=new MyCallbacks();

cb.add(fn1)

cb.add(fn2)

cb.add(fn3)

cb.remove(fn1)
cb.fire('hello')
cb.remove(fn3)
cb.fire('hello')
输出:

fn1 hello
fn2 hello
fn3 hello
----------------------------
fn1 hello
fn2 hello

2.测试has
var cb=new MyCallbacks();

cb.add(fn1)

cb.add(fn2)

cb.add(fn3)

cb.has(fn1)

cb.has(fn3)

输出:

false

---------------

true

3.测试带参数的构造函数 : once

var cb=new MyCallbacks('once')

cb.add(fn1)

cb.fire('hello')

cb.fire('hello')

cb.add(fn2)

cb.fire('hello')

输出:

hello

-------------------

------------------

------------------------------

4.测试带参数的构造函数 : memory

var cb=new MyCallbacks('memory')

cb.add(fn1)

cb.fire('hello') // 输出 : fn1 hello

cb.add(fn2) // 输出 : fn2 hello

cb.fire('hello')

输出 :

fn1 hello

fn2 hello

5.测试带参数的构造函数 : stopOnFalse

var cb=new MyCallbacks('stopOnFalse')

cb.add(fn1)

cb.add(fn2)

cb.add(fn3)

cb.fire('hello')

输出:

fn1 hello
fn2 hello
6.测试带参数的构造函数 :unique

var cb=new MyCallbacks('unique')

b.add(fn3)

b.add(fn3)

cb.fire('hello')

输出:

fn3 hello

7. 测试带组合参数的构造函数:四个设置参数可以随意组合,一下只测试全部组合的情况, 不然要写16个测试用例 T_T

var cb=new MyCallbacks('once memory unique stopOnFalse')

cb.add(fn1) // 输出: fn1

cb.add(fn2) // 输出: fn2

cb.add(fn3) //  输出: fn3

cb.fire('hello')

输出:

fn1 hello
fn2 hello
cb.fire('hello') // 输出:没有输出

以下是官方API 文档:

Description: A multi-purpose callbacks list object that provides a powerful way to manage callback lists.The $.Callbacks() function is internally used to provide the base functionality behind the jQuery $.ajax() and$.Deferred() components. It can be used as a similar base to define functionality for new components.

构造函数 : jQuery.Callbacks( flags )

flags
Type: String
An optional list of space-separated flags that change how the callback list behaves.
Possible flags:
once: Ensures the callback list can only be fired once (like a Deferred).
memory: Keeps track of previous values and will call any callback added after the list has been fired right away with the latest "memorized" values (like a Deferred).
unique: Ensures a callback can only be added once (so there are no duplicates in the list).
stopOnFalse: Interrupts callings when a callback returns false.
By default a callback list will act like an event callback list and can be "fired" multiple times.

Two specific methods were being used above: .add() and .fire(). The .add() method supports adding new callbacks to the callback list, while the .fire() method executes the added functions and provides a way to pass arguments to be processed by the callbacks in the same list.

利用Callbacks 实现发布订阅模式 pub/sub: (官方文档)

复制代码 代码如下:

var topics = {};

    jQuery.Topic = function ( id )
    {
      var callbacks,
        method,
        topic = id && topics[id];

      if ( !topic )
      {
        callbacks = jQuery.Callbacks();
        topic = {
          publish: callbacks.fire,
          subscribe: callbacks.add,
          unsubscribe: callbacks.remove
        };
        if ( id )
        {
          topics[id] = topic;
        }
      }
      return topic;
    };

使用

复制代码 代码如下:

$.Topic( 'mailArrived' ).subscribe( function ( e )
    {
      console.log( 'Your have new email! ' );
      console.log( "mail title : " + e.title );
      console.log( "mail content : " + e.content );
    }
    );

    $.Topic( 'mailArrived' ).publish( { title: 'mail title', content: 'mail content' } );

实现了其余的全部功能 :callbacks.disable , callbacks.disabled,  callbacks.fired,callbacks.fireWith, callbacks.lock, callbacks.locked ,然后重构了下代码结构, 将实现放入了匿名函数内, 然后通过工厂方法 window.callbacks 返回实例,以免每次使用必须 new .

具体代码如下, 有兴趣和时间的可以对照jQuery版本的Callbacks对比下 :
unity3d脚本http://www.unitymanual.com/

创新互联-专业网站定制、快速模板网站建设、高性价比锡林郭勒盟网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式锡林郭勒盟网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖锡林郭勒盟地区。费用合理售后完善,十年实体公司更值得信赖。

复制代码 代码如下:

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

另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


名称栏目:自己动手实现jQueryCallbacks完整功能代码详解-创新互联
文章起源:http://myzitong.com/article/pisis.html