3-6 jQuery回调模块结构
本节编程练习不计算学习进度,请电脑登录imooc.com操作

jQuery回调模块结构

整个$.Callbacks的源码很少,它是一个工厂函数,使用函数调用(非new,它不是一个类)创建对象,它有一个可选参数flags用来设置回调函数的行为,对外的接口也就是self的返回。

jQuery.Callbacks()的API列表如下:

callbacks.add()        :回调列表中添加一个回调或回调的集合。
callbacks.disable()    :禁用回调列表中的回调。
callbacks.disabled()   :确定回调列表是否已被禁用。 
callbacks.empty()      :从列表中删除所有的回调。
callbacks.fire()       :用给定的参数调用所有的回调。
callbacks.fired()      :访问给定的上下文和参数列表中的所有回调。 
callbacks.fireWith()   :访问给定的上下文和参数列表中的所有回调。
callbacks.has()        :确定列表中是否提供一个回调。
callbacks.lock()       :锁定当前状态的回调列表。
callbacks.locked()     :确定回调列表是否已被锁定。
callbacks.remove()     :从回调列表中的删除一个回调或回调集合。

源码结构:

jQuery.Callbacks = function(options) {
    options = typeof options === "string" ?
        (optionsCache[options] || createOptions(options)) :
        jQuery.extend({}, options);
    //实现代码
    fire = function() {}
    self = {
        add: function() {},
        remove: function() {},
        has: function(fn) {},
        empty: function() {},
        disable: function() {},
        disabled: function() {},
        lock: function() {},
        locked: function() {},
        fireWith: function(context, args) {},
        fire: function() {},
        fired: function() {}
    };
    return self;
};

整个结构要分三部分:

  ☑   Options参数缓存

  ☑   内部fire触发器的设计

  ☑   外部

参数的缓存设计

Callbacks是可以是接受的字符串的组合传参数,可以使用空格分割,代码如下:

var opts = 'unique memory';
var object = {}
jQuery.each(opts.match(/\S+/g) || [], function(_, flag) {
  object[flag] = true;
});

这样的操作其实是不需要重复的,所以我们可以设计一个缓存池,用来储存重复的操作:

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

所以我们传递参数的时候,如果参数是字符串,我们可以直接从optionsCache缓存中去查找:

options = typeof options === "string" ?
        ( optionsCache[ options ] || createOptions( options ) ) :
        jQuery.extend( {}, options );

接口的设计:

通过学习了观察者模式的思路,我们知道callback需要在内部维护着一个list的队列数组,用于保存订阅的对象数据。同时也需要提供了add、remove、fire等订阅、发布、删除类似的接口。

那么我们代码是不是很简单是就是把订阅对象给push给内部list列表?

实现思路就是: 构建一个存放回调的数组,如var list = [],通过闭包使这条回调数组保持存在。添加回调时,将回调push进list,执行则遍历list执行回调。

后面几节我们会通过简单的模拟实现去剖析设计的思路。

任务

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  5. <script src="http://img1.sycdn.imooc.com//down/540812440001e40e00000000.js" type="text/javascript"></script>
  6. <title></title>
  7. </head>
  8. <body>
  9.  
  10. <script type="text/javascript">
  11.  
  12. var optionsCache = {};
  13. var rnotwhite = (/\S+/g);
  14. // Convert String-formatted options into Object-formatted ones and store in cache
  15.  
  16. function show(data) {
  17. if (typeof data === 'object') {
  18. for (var key in data) {
  19. $("body").append('<li>key->' + key + '; value->'+ data[key] +'</li>')
  20. }
  21. } else {
  22. $("body").append('<li>' + data + '</li>')
  23. }
  24. }
  25.  
  26. function createOptions(options) {
  27. var object = optionsCache[options] = {};
  28. jQuery.each(options.match(rnotwhite) || [], function(_, flag) {
  29. object[flag] = true;
  30. });
  31. return object;
  32. }
  33.  
  34. function callback(options) {
  35. options = typeof options === "string" ?
  36. (optionsCache[options] || createOptions(options)) :
  37. jQuery.extend({}, options);
  38. show(options)
  39. }
  40.  
  41. callback('once memory')
  42.  
  43.  
  44. </script>
  45.  
  46. </body>
  47. </html>
下一节