$.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在一百多行的代碼裏就用到了兩種設計模式,確實經典。固然了這都是純屬我的看法。因爲平時用的不多,很遺憾沒有舉出表明性的例子供你們參考,畢竟我輩的目標是學以至用。