js高階函數

高階函數定義(至少知足下面條件之一的函數) - 《javascript 設計模式開發與實踐》

1.函數做爲形參傳遞
2.函數做爲返回值輸出javascript

1.函數做爲形式參數傳遞

a.回調函數(異步回調,達到異步執行條件將回調函數放入執行隊列中執行)
var appendDiv = function( callback ){ 
     for ( var i = 0; i < 100; i++ ){ 
         var div = document.createElement( 'div' ); 
         div.innerHTML = i; 
         document.body.appendChild( div ); 
         if ( typeof callback === 'function' ){ 
             callback( div ); 
         } 
     } 
}; 
appendDiv(function( node ){ 
 node.style.display = 'none'; 
});
b.Array.prototype.sort 類型函數 (Array.prototype.every - some - forEach - map - reduce 等等)

Array.prototype.sort 接受一個函數看成參數,這個函數裏面封裝了數組元素的排序規則。從Array.prototype.sort 的使用能夠看到,咱們的目的是對數組進行排序,這是不變的部分;而使用什麼規則去排序,則是可變的部分。把可變的部分封裝在函數參數裏,動態傳入
Array.prototype.sort,使 Array.prototype.sort 方法成爲了一個很是靈活的方法。html

let arr = [2,1,3];
arr.sort((a,b)=>{
    return a - b;        //a-b 從小到大,b-a 從大到小
})
console.log(arr);             //[1,2,3]

2.函數做爲返回值輸出(好比咱們最多見的閉包)

var getSingle = function ( fn ) { 
     var ret; 
     return function () { 
         return ret || ( ret = fn.apply( this, arguments ) ); 
 }; 
}; 
//這個高階函數的例子,既把函數看成參數傳遞,又讓函數執行後返回了另一個函數。咱們
//能夠看看 getSingle 函數的效果:
var getScript = getSingle(function(){ 
     return document.createElement( 'script' ); 
}); 
var script1 = getScript(); 
var script2 = getScript(); 
alert ( script1 === script2 ); // 輸出:true

3.高階函數實現AOP

AOP(面向切面編程)的主要做用是把一些跟核心業務邏輯模塊無關的功能抽離出來,這些跟業務邏輯無關的功能一般包括日誌統計、安全控制、異常處理等。把這些功能抽離出來以後,再經過「動態織入」的方式摻入業務邏輯模塊中。這樣作的好處首先是能夠保持業務邏輯模塊的純淨和高內聚性,其次是能夠很方便地複用日誌統計等功能模塊一般,在 JavaScript 中實現 AOP,都是指把一個函數「動態織入」到另一個函數之中,具體的實現技術有不少,本節咱們經過擴展 Function.prototype 來作到這一點。代碼以下:java

Function.prototype.before = function( beforefn ){ 
     var __self = this; // 保存原函數的引用
     return function(){ // 返回包含了原函數和新函數的"代理"函數
         beforefn.apply( this, arguments ); // 執行新函數,修正 this 
         return __self.apply( this, arguments ); // 執行原函數
     } 
}; 
Function.prototype.after = function( afterfn ){ 
     var __self = this; 
     return function(){ 
         var ret = __self.apply( this, arguments ); 
         afterfn.apply( this, arguments ); 
         return ret; 
     } 
}; 
var func = function(){ 
     console.log( 2 ); 
}; 
func = func.before(function(){ 
     console.log( 1 ); 
}).after(function(){ 
     console.log( 3 ); 
}); 
func();//1 2 3

4.柯里化(currying)

currying 又稱部分求值。一個 currying 的函數首先會接受一些參數,接受了這些參數以後,該函數並不會當即求值,而是繼續返回另一個函數,剛纔傳入的參數在函數造成的閉包中被保存起來。待到函數被真正須要求值的時候,以前傳入的全部參數都會被一次性用於求值。node

var cost = (function(){ 
     var args = []; 
     return function(){ 
         if ( arguments.length === 0 ){ 
             var money = 0; 
             for ( var i = 0, l = args.length; i < l; i++ ){ 
                 money += args[ i ]; 
            } 
             return money; 
         }else{ 
             [].push.apply( args, arguments ); 
         } 
     } 
})(); 
cost( 100 ); // 未真正求值
cost( 200 ); // 未真正求值
cost( 300 ); // 未真正求值
console.log( cost() ); // 求值並輸出:600

5.節流 - 函數被觸發的頻率過高。

實現:經過閉包來實現
一個簡單的例子:ajax

//節流
let jieliu = (function (){
    let ajax = true;
    return function(){
        console.log(ajax);
        if(ajax){
            ajax = false;
            let time = setTimeout(function(){
            ajax = true;
            console.log('ajaxing');
        },5000);
        }
    }
})();
document.getElementById('test').onclick = jieliu;

6.分時函數

某些函數確實是用戶主動調用的,但由於一些客觀的緣由,這些函數會嚴重地影響頁面性能在短期內往頁面中大量添加 DOM 節點顯然也會讓瀏覽器吃不消,咱們看到的結果每每就是瀏覽器的卡頓甚至假死。代碼以下:編程

var ary = []; 
for ( var i = 1; i <= 10000000; i++ ){ 
     ary.push( i ); // 假設 ary 裝載了 10000000 個好友的數據
}; 
var renderFriendList = function( data ){ 
     for ( var i = 0, l = data.length; i < l; i++ ){ 
         var div = document.createElement( 'div' ); 
         div.innerHTML = i; 
         document.body.appendChild( div ); 
     } 
}; 
renderFriendList( ary );   //哈哈,界面直接提示崩潰啦

解決方案:分時函數 - 利用setTimeout 每隔一段時間建立dom節點加入界面中,緩解一次性添加過多dom結點形成的低性能問題設計模式

var timeChunk = function( ary, fn, count ){ 
    var obj, 
        t; 
    var len = ary.length; 
    var start = function(){ 
        for ( var i = 0; i < Math.min( count || 1, ary.length ); i++ ){ 
            var obj = ary.shift(); 
            fn( obj ); 
        } 
    }; 
    return function(){ 
        t = setInterval(function(){ 
        if ( ary.length === 0 ){ // 若是所有節點都已經被建立好
            return clearInterval( t ); 
        } 
        start(); 
        }, 200 ); // 分批執行的時間間隔,也能夠用參數的形式傳入
    }; 
}; 

 var ary = []; 
 for ( var i = 1; i <= 10000000; i++ ){ 
    ary.push( i ); 
 }; 
 var renderFriendList = timeChunk( ary, function( n ){ 
    var div = document.createElement( 'div' ); 
    div.innerHTML = n; 
    document.body.appendChild( div ); 
 }, 12 ); 
 renderFriendList();

7.惰性加載函數

在 Web 開發中,由於瀏覽器之間的實現差別,一些嗅探工做老是不可避免。好比咱們須要一個在各個瀏覽器中可以通用的事件綁定函數 addEvent
新手寫法:數組

var addEvent = function( elem, type, handler ){ 
     if ( window.addEventListener ){ 
         return elem.addEventListener( type, handler, false ); 
    } 
     if ( window.attachEvent ){ 
         return elem.attachEvent( 'on' + type, handler ); 
     } 
}; //缺點是當它每次被調用的時候都會執行裏面的 if 條件分支,雖然執行這些 if分支的開銷不算大,但也許有一些方法可讓程序避免這些重複的執行過程。

進階寫法:瀏覽器

var addEvent = (function(){ 
     if ( window.addEventListener ){ 
         return function( elem, type, handler ){ 
             elem.addEventListener( type, handler, false ); 
         } 
     } 
     if ( window.attachEvent ){ 
         return function( elem, type, handler ){ 
            elem.attachEvent( 'on' + type, handler ); 
         } 
     } 
})();  //咱們把嗅探瀏覽器的操做提早到代碼加載的時候,在代碼加載的時候就馬上進行一次判斷,以便讓 addEvent 返回一個包裹了正確邏輯的函數。

缺點:也許咱們從頭至尾都沒有使用過 addEvent 函數,這樣看來,前一次的瀏覽器嗅探就是徹底多餘的操做,並且這也會稍稍延長頁面 ready 的時間。安全

老司機寫法: - 惰性載入函數方案

<html> 
  <body> 
   <div id="div1">點我綁定事件</div> 
   <script> 
         var addEvent = function( elem, type, handler ){ 
                 if ( window.addEventListener ){ 
                     addEvent = function( elem, type, handler ){ 
                         elem.addEventListener( type, handler, false ); 
                     } 
                 }else if ( window.attachEvent ){ 
                     addEvent = function( elem, type, handler ){ 
                         elem.attachEvent( 'on' + type, handler ); 
                     } 
                 } 
                 addEvent( elem, type, handler ); 
         }; 
        var div = document.getElementById( 'div1' ); 
             addEvent( div, 'click', function(){ 
             alert (1); 
         }); 
        addEvent( div, 'click', function(){ 
            alert (2); 
        }); 
 </script> 
 </body> 
</html>
相關文章
相關標籤/搜索