JavaScriptの高次関数の魅力


高次関数とは、少なくとも次の条件を満たす関数の1つである.関数はパラメータとして伝達され得る.2:関数は戻り値として出力され得る.
JavaScript                    ,         JavaScript        。
高次関数実現AOP
AOP(面に向かってプログラミングする)の主な役割はコア業務論理モジュールとは無関係な機能を抽出し、その後「動的に織り込む」方式で業務モジュールに組み込むことです.これらの機能は一般にログ統計、セキュリティ制御、異常処理などを含む.AOPはJava Springアーキテクチャの核心である.次に、Javascript種はどうやってAOPを実現するかを探ってみます.
JavaScriptの種類でAOPを実現するということは、一つの関数「動的編入」を他の関数に組み込むということです.具体的に実現される技術はたくさんあります.私たちはFunction.prototypeを使ってこの点を達成します.コードは以下の通りです
/**
*        
* @param {*} fn 
*/
Function.prototype.aopBefore = function(fn){
  console.log(this)
  //    :        
  const _this = this
  //    :            “  ”  
  return function() {
    //    :     ,  this
    fn.apply(this, arguments)
    //          
    return _this.apply(this, arguments)
  }
}
/**
*        
* @param {*} fn 
*/
Function.prototype.aopAfter = function (fn) {
  const _this = this
  return function () {
    let current = _this.apply(this,arguments)//       
    fn.apply(this, arguments) //       
    return current
  }
}
/**
*     
*/
let aopFunc = function() {
  console.log('aop')
}
//     
aopFunc = aopFunc.aopBefore(() => {
  console.log('aop before')
}).aopAfter(() => {
  console.log('aop after')
})
//     
aopFunc()
currying(カリー化)
curringについてまず何を話しますか?関数コリック化です.
curringはまた部分の価値を求めます.一つ
curringの関数は、まずいくつかのパラメータを受け入れ、これらのパラメータを受け入れた後、この関数はすぐに値を求めず、20は別の関数に戻り続け、先ほど入ってきたパラメータは関数によって形成されたクローズドに保存される.関数で本当に値を求める必要があるときは、その前に伝えられたすべてのパラメータを一度に値を求めるために使います.
硬い概念はよく分かりません.次の例を見てみます.一年の12ヶ月の消費を計算する関数が必要です.毎月の月末に私達はどれぐらいの金額を計算しますか?正常コードは以下の通りです
//            
let totalCost = 0
const cost = function(amount, mounth = '') {
 console.log(` ${mounth}     ${amount}`)
 totalCost += amount
 console.log(`      :${totalCost}`)
}
cost(1000, 1) //  1     
cost(2000, 2) //  2     
// ...
cost(3000, 12) //  12     
まとめてみます.一年間の総消費を計算するなら、12回計算する必要はありません.年末に計算を一回実行すればいいです.これからはこの関数の部分的なコリゼーションの関数を理解してくれます.
//          
const curringPartCost = (function() {
 //     
 let args = []
 return function (){
   /**
    *          
    *            
    *            
    */
   if (arguments.length === 0) {
     let totalCost = 0
     args.forEach(item => {
       totalCost += item[0]
     })
     console.log(`   :${totalCost}`)
     return totalCost
   } else {
     // argumens     ,        
     let currentArgs = Array.from(arguments)
     args.push(currentArgs)
     console.log(`  ${arguments[1] ? arguments[1] : '' } ,  ${arguments[0]}`)
   }
 }
})()
curringPartCost(1000,1)
curringPartCost(100,2)
curringPartCost()
次に一般的なcurringを作成し,間もなくcurringの関数になる.コードは以下の通りです
//   curring  
const curring = function(fn) {
 let args = []
 return function () {
   if (arguments.length === 0) {
     console.log('curring        ')
     return fn.apply(this, args)
   } else {
     let currentArgs = Array.from(arguments)[0]
     console.log(`  ${arguments[1] ? arguments[1] : '' } ,  ${arguments[0]}`)
     args.push(currentArgs)
     //         Function   ,        Function      ,                     
     return arguments.callee
   }
 }
}
//     
let costCurring = (function() {
 let totalCost = 0
 return function () {
   for (let i = 0; i < arguments.length; i++) {
     totalCost += arguments[i]
   }
   console.log(`   :${totalCost}`)
   return totalCost
 }
})()
//   curring 
costCurring = curring(costCurring)
costCurring(2000, 1)
costCurring(2000, 2)
costCurring(9000, 12)
costCurring()
󑧙葃関数節流JavaScriptの大多数の関数はユーザーが主導的にトリガしたもので、一般的には性能の問題はないが、いくつかの特殊な状況ではユーザーによって直接制御されない.大量の呼び出しがしやすく、性能に問題があります.なにしろDOM動作の価格は非常に高価である.以下では、このような場面をいくつか挙げます.
  • window.resise事件です.
  • mouse, inputなどの事件.
  • アップロードの進捗度
  • 次は高次関数の方法で関数節流を実現します.
    /**
    *     
    * @param {*} fn 
    * @param {*} interval 
    */
    const throttle = function (fn, interval = 500) {
     let timer = null, //     
         isFirst = true //         
     return function () {
       let args = arguments, _me = this
       //         
       if (isFirst) {
         fn.apply(_me, args)
         return isFirst = false
       }
       //         
       if (timer) {
         return false
       }
       //   timer
       timer = setTimeout(function (){
        console.log(timer)
        window.clearTimeout(timer)
        timer = null
        fn.apply(_me, args)
       }, interval)
     }
    }
    //     
    window.onresize = throttle(function() {
     console.log('throttle')
    },600)
    時分関数
    流れ関数は頻繁に呼び出される制限関数の解を提供してくれる.次はもう一つの問題があります.いくつかの関数はユーザーから積極的に呼び出されますが、いくつかの客観的な原因で、これらの操作はページの性能に深刻な影響を与えます.この時は別の方法で解決しなければなりません.
    もし私たちが短い時間でページに大量のDOMノードを挿入する必要があるなら、それは明らかにブラウザを辛くさせます.ブラウザの仮死を引き起こす可能性がありますので、分時関数を使って、いくつかのグループに分けて挿入します.
    /**
    *     
    * @param {*         } list 
    * @param {*        } fn 
    * @param {*        } count 
    */
    const timeChunk = function(list, fn, count = 1){
     let insertList = [], //          
         timer = null //    
     const start = function(){
       //            
       for (let i = 0; i < Math.min(count, list.length); i++) {
         insertList = list.shift()
         fn(insertList)
       }
     }
     return function(){
       timer = setInterval(() => {
         if (list.length === 0) {
           return window.clearInterval(timer)
         }
         start()
       },200)
     }
    }
    //       
    const arr = []
    for (let i = 0; i < 94; i++) {
     arr.push(i)
    }
    const renderList = timeChunk(arr, function(data){
     let div =document.createElement('div')
     div.innerHTML = data + 1
     document.body.appendChild(div)
    }, 20)
    renderList()
    不活性負荷関数
    Web開発では、いくつかのブラウザの違いのため、いくつかの嗅覚作業が避けられない.
    ブラウザの差異性のために、私たちは常に様々な互換性を持っています.非常に簡単で一般的な例を挙げてください.各ブラウザで通用するイベントバインディング関数です.
    よくある書き方はこうです.
    //        
    const addEvent = function(el, type, handler) {
     if (window.addEventListener) {
       return el.addEventListener(type, handler, false)
     }
     // for IE
     if (window.attachEvent) {
       return el.attachEvent(`on${type}`, handler)
     }
    }
    この関数は実行するたびにif条件分岐を実行する欠点がある.お金はあまりかかりませんが、これは明らかに余分です.次は最適化して、事前に嗅いでみましょう.
    const addEventOptimization = (function() {
     if (window.addEventListener) {
       return (el, type, handler) => {
         el.addEventListener(type, handler, false)
       }
     }
     // for IE
     if (window.attachEvent) {
       return (el, type, handler) => {
         el.attachEvent(`on${type}`, handler)
       }
     }
    })()
    このようにコードを読み込む前に一回嗅覚を行い、関数を返します.しかし、私たちがそれを公共の倉庫に入れて使用しないと、ちょっと余分です.以下は不活性関数を使ってこの問題を解決します.
    //       
    let addEventLazy = function(el, type, handler) {
     if (window.addEventListener) {
       //       ,             
       addEventLazy = function(el, type, handler) {
         el.addEventListener(type, handler, false)
       }
     } else if (window.attachEvent) {
       addEventLazy = function(el, type, handler) {
         el.attachEvent(`on${type}`, handler)
       }
     }
     addEventLazy(el, type, handler)
    }
    addEventLazy(document.getElementById('eventLazy'), 'click', function() {
     console.log('lazy ')
    })
    分岐に入ると、関数の内部で関数の実装を変更し、書き換えた後、関数は私たちが期待する関数であり、次の関数に入ると条件分岐文は存在しなくなります.
    締め括りをつける
    この文章は主に「Javascriptデザインモード」のまとめを読んでいます.
    コードアドレス
    原文の住所