JavaScript 觀察者模式

2018-08-02 16:26 更新

觀察者模式

另一個我們之前提到過的模式就是觀察者(發(fā)布/訂閱)模式.這種模式下,系統(tǒng)中的對象可以在關(guān)注的事件發(fā)生的時候給其他對象發(fā)送消息,也可以被其他對象所通知。

jQuery核心庫很多年前就已經(jīng)提供了對于類似于發(fā)布/訂閱系統(tǒng)的支持,它們稱之為定制事件。

jQuery的早期版本中,可以通過使用jQuery.bind()(訂閱),jQuery.trigger()(發(fā)布),和jQuery.unbind()(取消訂閱)來使用這些定制事件,但在近期的版本中,這些都可以通過使用jQuery.on(),jQuery.trigger()和jQuery.off()來完成。

下面我們來看一下實際應(yīng)用中的一個例子:

// Equivalent to subscribe(topicName, callback)
$( document ).on( "topicName" , function () {
    //..perform some behaviour
});

// Equivalent to publish(topicName)
$( document ).trigger( "topicName" );

// Equivalent to unsubscribe(topicName)
$( document ).off( "topicName" );

對于jQuery.on()和jQuery.off()的調(diào)用最后會經(jīng)過jQuery的事件系統(tǒng),與Ajax一樣,由于它們的實現(xiàn)代碼相對較長,我們只看一下實際上事件處理器是在哪兒以及如何將定制事件加入到系統(tǒng)中的:

jQuery.event = {

  add: function( elem, types, handler, data, selector ) {

    var elemData, eventHandle, events,
      t, tns, type, namespaces, handleObj,
      handleObjIn, quick, handlers, special;

    ...

    // Init the element's event structure and main handler,
    //if this is the first
    events = elemData.events;
    if ( !events ) {
      elemData.events = events = {};
    }
    ...

    // Handle multiple events separated by a space
    // jQuery(...).bind("mouseover mouseout", fn);
    types = jQuery.trim( hoverHack(types) ).split( " " );
    for ( t = 0; t < types.length; t++ ) {

      ...

      // Init the event handler queue if we're the first
      handlers = events[ type ];
      if ( !handlers ) {
        handlers = events[ type ] = [];
        handlers.delegateCount = 0;

        // Only use addEventListener/attachEvent if the special
        // events handler returns false
        if ( !special.setup || special.setup.call( elem, data,
        //namespaces, eventHandle ) === false ) {
          // Bind the global event handler to the element
          if ( elem.addEventListener ) {
            elem.addEventListener( type, eventHandle, false );

          } else if ( elem.attachEvent ) {
            elem.attachEvent( "on" + type, eventHandle );
          }
        }
      }

對于那些喜歡使用傳統(tǒng)的命名方案的人, Ben Alamn對于上面的方法提供了一個簡單的包裝,然后為我們提供了jQuery.publish(),jQuery.subscribe和jQuery.unscribe方法。我之前在書中提到過,現(xiàn)在我們可以完整的看一下這個包裝器。

(function( $ ) {

  var o = $({});

  $.subscribe = function() {
    o.on.apply(o, arguments);
  };

  $.unsubscribe = function() {
    o.off.apply(o, arguments);
  };

  $.publish = function() {
    o.trigger.apply(o, arguments);
  };

}( jQuery ));

在近期的jQuery版本中,一個多目的的回調(diào)對象(jQuery.Callbacks)被提供用來讓用戶在回調(diào)列表的基礎(chǔ)上寫新的方案。另一個發(fā)布/訂閱系統(tǒng)就是一個使用這個特性寫的方案,它的實現(xiàn)方式如下:

var topics = {};

jQuery.Topic = function( id ) {
    var callbacks,
        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;
};

然后可以像下面一樣使用:

// Subscribers
$.Topic( "mailArrived" ).subscribe( fn1 );
$.Topic( "mailArrived" ).subscribe( fn2 );
$.Topic( "mailSent" ).subscribe( fn1 );

// Publisher
$.Topic( "mailArrived" ).publish( "hello world!" );
$.Topic( "mailSent" ).publish( "woo! mail!" );

//  Here, "hello world!" gets pushed to fn1 and fn2
//  when the "mailArrived" notification is published
//  with "woo! mail!" also being pushed to fn1 when
//  the "mailSent" notification is published.

// Outputs:
// hello world!
// fn2 says: hello world!
// woo! mail!
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號