原生JS技巧(2)淺談回調函數(攔截器、注入和控制反轉原理)


  現在很多框架都在說攔截器、依賴注入、控制反轉,尤其是java,很多的js框架也引入這種設計思想,包括angular、vue等等,在網上一查也有好多關於這方面的文章,但技術性有很深,但讀過源碼的人應該就明白它核心的原理,由大到小來解釋就是“回調函數”。

1、回調函數

  什么是“回調函數”,看下面例子

1 var list = [{a:1,b:2,c:3},{a:3,b:4,c:5},{a:4,b:3,c:2},{a:7,b:1,c:1}];
2 list.filter(function(item){
3 return item.a > 3;
4 });

filter是Array的一個函數,正常我們會list.filter()這么調用,來篩選數組,

如果所有的邏輯都寫在filter()內部,我們需要大量的判斷條件,在不清楚list數組內容的情況,就無法去寫filter的條件,

這樣我們就需要把控制權交給外面,里面只提供基礎功能,用於返回新數組。

那我們自己寫一個回調,如下:

1 var filter = function(array,callback){
2 var _array = [];
3 for(var i in array){
4 if(callback.call(this,array[i])) _array.push(array[i]);
5 }
6 }

由此能看出,回調函數就是參數只傳入一個函數體,而函數內部執行作為參數的這個函數。

 

2、攔截器

很多語言都有攔截器,而攔截器的原理和回調函數很像,也是把部分的控制權交給了外部,而內部只是調用包含外部控制權的函數

var c = function(callback){
    var b = 0;
    setInterval(function(){
        b += 1;
        if(b % 3 === 0){
            callback.apply(this,[b*1000]);
        }
    },1000)
}
var a = [];
c(function(val){
    a.push(val);
});

a的值: [3000, 6000, 9000, ...] ,會按照每3秒的時間攔截一次,並向a數組中添加

我們在外部可以任意定義callback中的邏輯,如果c函數內部是一個ajax請求或其他異步,我們需要捕捉請求回來時變量被賦值,或者捕捉模塊加載完成時,都可以在需要的節點下調用一個回調函數,並把內部獲取的數據通過參數返回給外部,像:callback.apply(this指向的對象,[參數]),外部可以任意控制處理,這就是攔截器的基本原理。

 

3、控制反轉和依賴注入

我們也可以用回調來實現,先簡單理解下控制反轉和依賴注入,首先依賴注入是控制反轉的實現,

我們每次實例化對象的時候,都會現new一個新的對象,像var a = new b()

然后用a.xxx的方式來使用b中的屬性和方法,但有一個地方調b的對象,要用到b里y1 : function(),另一個地方也調b對象,卻不能有y1 : function(),

這樣我們就不方便把控制權交給b對象,而是放在外面,而里面只需要讓它自動new一個對象,這就是注入

簡單來說就是外部只需要傳入類的引用,外部就可以直接調用它的對象。

 1 export class SummaryComponent implements OnInit, AfterViewInit {
 2   constructor(public http: Http){
 3 
 4   ngOnInit() {
 5     //XHR異步請求:發送get請求
 6      this.http.get('./app/contact360/summary.sub.component.html').subscribe(data => {
 7         alert(data.text()); //如果請求的是文本:  data.text() ,  如果請求的是json文件:  data.json()
 8      });
 9   }
10 }

這是angular2注入的例子,在構造方法中傳入Http這個類,正常我需要 this.http = new Http()

但現在我把new的控制權交給了angular,使它在實例化SummaryComponent的時候,順便把構造方法中傳入的類都實例化了,並反給自身,

這樣,我們就可以不用new而直接可以調用this.http的對象,這么做也有個好處就是,new Http()的時候,我不知道傳什么參數給它,而現在我也不用考慮這個了。

問:這和回調函數有什么關系?

答:都是把控制權交給外面,里面只做基本操作

 1 define(["demo"],function(_demo){ return new _demo(); }); 

知道模塊化開發的同學都知道上面這個用於引入新外來模塊用的,但如果define我這么寫

1 _define = function(mods,func){
2     var _objs = [];
3     define(mods,function(){
4          for(var i=0;i<arguments.length;i++){
5              _objs.push(new arguments[i]);
6          }
7     });
8     func.apply(this,_objs);
9 }

用的時候我就不用new _demo()了,並可以直接用_demo.test()對象方法了

 1 _define(["demo"],function(_demo){ return _demo.test(); }); 

這就是通過回調函數來注入,

當然注入對象的主要還是通過調用接口和繼承的方式,但原理依然脫離不了這種方式,

雖然原理很簡單,但結合各種設計模式后,就會奧妙無窮。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM