$.Callbacks用来管理函数队列。采用了观察者模式,经过add添加操做到队列当中,经过fire去执行这些操做。实际上$.Callbacks是1.7版本从$.Deferred对象当中分离出来的,主要是实现$.Deferred功能。设计模式
咱们经过调用$.Callbacks获取到一个callback实例,以下数组
var cb = $.Callbacks();
看到Callbacks首字母大写,有些人可能会以为通常只有对象才会这样,所以须要new一个实例,以下闭包
var cb = new $.Callbacks();
实际上这两种方式均可以,由于Callbacks函数返回值是一个对象,为何会这样?看下面一组对比函数
function Cons() { this.name = 'this.name'; return { name: 'obj.name' }; } console.log(Cons().name);//obj.name console.log(new Cons().name);//obj.name function Cons() { this.name = 'this.name'; return 'str.name'; } console.log(Cons());//str.name console.log(new Cons().name);//this.name
当函数的返回值是一个对象时(null除外),new和直接调用二者的返回值是同样的。可是须要注意了,二者的this指向是不同的。为了尽量的节省代码和避免混乱咱们仍是统一采用var cb = $.Callbacks();的方式去调用。this
像这种先调用获取到实例,而后经过实例进行一系列的操做,很明显利用了闭包特性。设计
向内部队列添加函数,总有三种参数形式code
var cb = $.Callbacks(); cb.add(function () { console.log('add one'); });
var cb = $.Callbacks(); cb.add(function () { console.log('add one'); }, function () { console.log('add two'); });
var cb = $.Callbacks(); cb.add([ function () { console.log('add one'); }, function () { console.log('add two'); } ]);
依次执行队列里的函数对象
var cb = $.Callbacks(); cb.add([ function () { console.log('add one'); }, function () { console.log('add two'); } ]); cb.fire(); //add one //add two
fire的参数会传递给咱们添加的函数,例如队列
var cb = $.Callbacks(); cb.add(function (name, age) { console.log(name, age); }); cb.fire('Jacky', 26);//Jacky 26
fire调用的时候,咱们添加函数当中的this指向咱们的Callbacks实例,例如rem
var cb = $.Callbacks(); cb.add(function () { console.log(this === cb); }); cb.fire();//true
fireWith就是改变咱们添加函数的context,即this指向,例如
var cb = $.Callbacks(); var obj = { name: 'objName' }; cb.add(function (age) { console.log(this.name, age); }); cb.fireWith(obj, [26]);//objName 26
fireWith第一个参数是咱们的context,第二个参数是咱们须要传递的内容数组,注意了是数组!
清空函数队列
var cb = $.Callbacks(); cb.add(function () { console.log('add one'); }); cb.empty(); cb.fire();
判断函数队列中是否存在某个函数
var cb = $.Callbacks(); function demo() { console.log('demo'); } cb.add(demo); console.log(cb.has(demo));//true
函数传递的都是引用,千万别出现如下的低级错误
var cb = $.Callbacks(); cb.add(function () { console.log('demo'); }); cb.has(function () { console.log('demo'); });
从内部队列中移除某些函数
var cb = $.Callbacks(); function demo1() { console.log('demo1'); } function demo2() { console.log('demo2'); } cb.add(demo1, demo2); cb.remove(demo1, demo2); cb.fire();
禁用回调列表。这种状况会清空函数队列,禁用核心功能。意味着这个回调管理报废了。
var cb = $.Callbacks(); cb.add(function () { console.log('add'); }); cb.disable(); cb.fire();
回调管理是否被禁用
var cb = $.Callbacks(); cb.add(function () { console.log('add'); }); cb.disable(); console.log(cb.disabled());//true
锁定回调管理,同disable,惟一的差异会在下面表述
回调管理是否被锁
回调队列是否执行过
var cb = $.Callbacks(); cb.add(function () { console.log('add'); }); cb.fire();//add console.log(cb.fired());//true
$.Callbacks经过字符串参数的形式支持4种及以上的特定功能。很明显的一个工厂模式。
函数队列只执行一次。参考如下对比
//不添加参数 var cb = $.Callbacks(); cb.add(function () { console.log('add'); }); cb.fire();//add cb.fire();//add //添加参数 var cb = $.Callbacks('once'); cb.add(function () { console.log('add'); }); cb.fire();//add cb.fire();
函数队列执行过之后,就不会在执行了,不管调用fire多少次。
往内部队列添加的函数保持惟一,不能重复添加。参考如下对比
//不添加参数 var cb = $.Callbacks(); function demo() { console.log('demo'); } cb.add(demo, demo); cb.fire(); //demo //demo //添加参数 var cb = $.Callbacks('unique'); function demo() { console.log('demo'); } cb.add(demo, demo); cb.fire();//demo
相同的函数不会被重复添加到内部队列中
内部队列里的函数是依次执行的,当某个函数的返回值是false时,中止继续执行剩下的函数。参考如下对比
//不添加参数 var cb = $.Callbacks(); cb.add([ function () { console.log('add one'); }, function () { console.log('add two'); } ]); cb.fire(); //add one //add two //添加参数 var cb = $.Callbacks('stopOnFalse'); cb.add([ function () { console.log('add one'); return false; }, function () { console.log('add two'); } ]); cb.fire();//add one
注意了返回值必定要是false,像undefined、null这种做为返回值是没有效果的
当函数队列fire或fireWith一次事后,内部会记录当前fire或fireWith的参数。当下次调用add的时候,会把记录的参数传递给新添加的函数并当即执行这个新添加的函数。看个例子
var cb = $.Callbacks('memory'); cb.add(function (name) { console.log('one', name); }); cb.fire('Jacky');//first Jacky cb.add(function (name) { console.log('two', name); });//two Jacky
例如公司领导在9点的时候发了封邮件,要求你们提交本身的年终终结,这就至关于fire操做了,在公司里的员工收到邮件后,立马提交了。小李因为请假,下午才过来,看到邮件后也提交了本身的年终总结。不须要领导再次发送邮件提醒。
fire或fireWith必定要在disabled或lock前先执行一遍,memory才会起做用
这四种基本类型能够相互组合起来使用,例如$.Deferred就使用了once和memory的组合。
jQuery.Callbacks("once memory")
二者惟一的区别就是添加了memory参数,看一下对比
var cb = $.Callbacks('memory'); cb.add(function () { console.log('one'); }); cb.fire(); cb.disable(); //cb.lock(); cb.add(function () { console.log('two'); });
毫无疑问,disable就是禁用全部功能,不管添加什么参数。而在memory的状况下,fire事后在lock,继续add新的函数依旧会当即执行。
$.Callbacks在一百多行的代码里就用到了两种设计模式,确实经典。固然了这都是纯属我的看法。因为平时用的不多,很遗憾没有举出表明性的例子供你们参考,毕竟我辈的目标是学以至用。