<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] # 柯里化到底是什么 > 維基百科上說道:柯里化,英語:Currying(果然是滿滿的英譯中的既視感),是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,并且返回接受余下的參數而且返回結果的新函數的技術。 ~~~jsx // 普通的add函數 function add(x, y) { return x + y } // Currying后 function curryingAdd(x) { return function (y) { return x + y } } add(1, 2) // 3 curryingAdd(1)(2) // 3 ~~~ # Currying有哪些好處呢? ## 參數復用 ~~~jsx // 正常正則驗證字符串 reg.test(txt) // 函數封裝后 function check(reg, txt) { return reg.test(txt) } check(/\d+/g, 'test') //false check(/[a-z]+/g, 'test') //true // Currying后 function curryingCheck(reg) { return function(txt) { return reg.test(txt) } } var hasNumber = curryingCheck(/\d+/g) var hasLetter = curryingCheck(/[a-z]+/g) hasNumber('test1') // true hasNumber('testtest') // false hasLetter('21212') // false ~~~ 上面的示例是一個正則的校驗,正常來說直接調用check函數就可以了,但是如果我有很多地方都要校驗是否有數字,其實就是需要將第一個參數reg進行復用,這樣別的地方就能夠直接調用hasNumber,hasLetter等函數,讓參數能夠復用,調用起來也更方便。 ## 提前確認 ~~~jsx var on = function(element, event, handler) { if (document.addEventListener) { if (element && event && handler) { element.addEventListener(event, handler, false); } } else { if (element && event && handler) { element.attachEvent('on' + event, handler); } } } var on = (function() { if (document.addEventListener) { return function(element, event, handler) { if (element && event && handler) { element.addEventListener(event, handler, false); } }; } else { return function(element, event, handler) { if (element && event && handler) { element.attachEvent('on' + event, handler); } }; } })(); //換一種寫法可能比較好理解一點,上面就是把isSupport這個參數給先確定下來了 var on = function(isSupport, element, event, handler) { isSupport = isSupport || document.addEventListener; if (isSupport) { return element.addEventListener(event, handler, false); } else { return element.attachEvent('on' + event, handler); } } ~~~ 我們在做項目的過程中,封裝一些dom操作可以說再常見不過,上面第一種寫法也是比較常見,但是我們看看第二種寫法,它相對一第一種寫法就是自執行然后返回一個新的函數,這樣其實就是提前確定了會走哪一個方法,避免每次都進行判斷。 ## 延遲運行 ~~~jsx Function.prototype.bind = function (context) { var _this = this var args = Array.prototype.slice.call(arguments, 1) return function() { return _this.apply(context, args) } } ~~~ 像我們js中經常使用的bind,實現的機制就是Currying. ## 提高適用性 **通用函數**解決了兼容性問題,但同時也會再來,使用的不便利性,不同的應用場景往,要傳遞很多參數,以達到解決特定問題的目的。有時候應用中,同一種規則可能會反復使用,這就可能會造成代碼的重復性。 ~~~ // 未柯里化前 function square(i) { return i * i; } function dubble(i) { return i * 2; } function map(handler, list) { return list.map(handler); } map(square, [1, 2, 3, 4, 5]); // 數組的每一項平方 map(square, [6, 7, 8, 9, 10]); map(dubble, [1, 2, 3, 4, 5]); // 數組的每一項加倍 map(dubble, [6, 7, 8, 9, 10]); ~~~ 同一規則重復使用,帶來代碼的重復性,因此可以使用上面的通用柯里化實現改造一下: ~~~ // 柯里化后 function square(i) { return i * i; } function dubble(i) { return i * 2; } function map(handler, ...list) { return list.map(handler); } var mapSQ = currying(map, square); mapSQ([1, 2, 3, 4, 5]); mapSQ([6, 7, 8, 9, 10]); var mapDB = currying(map, dubble); mapDB([1, 2, 3, 4, 5]); mapDB([6, 7, 8, 9, 10]); ~~~ 可以看到這里柯里化方法的使用和偏函數比較類似,順便回顧一下偏函數~ **偏函數**是創建一個調用另外一個部分(參數或變量已預制的函數)的函數,函數可以根據傳入的參數來生成一個真正執行的函數。比如: ~~~ const isType = function(type) { return function(obj) { return Object.prototype.toString.call(obj) === `[object ${type}]` } } const isString = isType('String') const isFunction = isType('Function') ~~~ 這樣就用偏函數快速創建了一組判斷對象類型的方法~ **偏函數**固定了函數的某個部分,通過傳入的參數或者方法返回一個新的函數來接受剩余的參數,數量可能是一個也可能是多個 **柯里化**是把一個有n個參數的函數變成n個只有1個參數的函數,例如:`add = (x, y, z) => x + y + z`→`curryAdd = x => y => z => x + y + z` 當偏函數接受一個參數并且返回了一個只接受一個參數的函數,與兩個接受一個參數的函數curry()()的柯里化函數,這時候兩個概念類似。(個人理解不知道對不對) <br> <br> # 通用的封裝方法 ~~~jsx // 初步封裝 function currying(fn, ...rest1) { return function(...rest2) { return fn.apply(null, rest1.concat(rest2)) } } ~~~ 注意這里concat接受非數組元素參數將被當做調用者的一個元素傳入 用它將一個sayHello函數柯里化試試: ~~~ function sayHello(name, age, fruit) { console.log(console.log(`我叫 ${name},我 ${age} 歲了, 我喜歡吃 ${fruit}`)) } const curryingShowMsg1 = currying(sayHello, '小明') curryingShowMsg1(22, '蘋果') // 我叫 小明,我 22 歲了, 我喜歡吃 蘋果 const curryingShowMsg2 = currying(sayHello, '小衰', 20) curryingShowMsg2('西瓜') // 我叫 小衰,我 20 歲了, 我喜歡吃 西瓜 ~~~ <br> <br> 以上柯里化函數已經能解決一般需求了,但是如果要多層的柯里化總不能不斷地進行currying函數的嵌套吧,我們希望經過柯里化之后的函數每次只傳遞一個或者多個參數,那該怎么做呢: ~~~jsx function curryingHelper(fn, len) { const length = len || fn.length // 第一遍運行length是函數fn一共需要的參數個數,以后是剩余所需要的參數個數 return function(...rest) { return rest.length >= length // 檢查是否傳入了fn所需足夠的參數 ? fn.apply(this, rest) : curryingHelper(currying.apply(this, [fn].concat(rest)), length - rest.length) // 在通用currying函數基礎上 } } function sayHello(name, age, fruit) { console.log(`我叫 ${name},我 ${age} 歲了, 我喜歡吃 ${fruit}`) } const betterShowMsg = curryingHelper(sayHello) betterShowMsg('小衰', 20, '西瓜') // 我叫 小衰,我 20 歲了, 我喜歡吃 西瓜 betterShowMsg('小豬')(25, '南瓜') // 我叫 小豬,我 25 歲了, 我喜歡吃 南瓜 betterShowMsg('小明', 22)('倭瓜') // 我叫 小明,我 22 歲了, 我喜歡吃 倭瓜 betterShowMsg('小拽')(28)('冬瓜') // 我叫 小拽,我 28 歲了, 我喜歡吃 冬瓜 ~~~ 如此實現一個高階的柯里化函數,使得柯里化一個函數的時候可以不用嵌套的currying,當然是因為把嵌套的地方放到了curryingHelper里面進行了 <br> <br> # 不限定參數 ~~~ function sumWithES6(...rest) { var _args = rest; var _adder = function (...innerRest) { _args.push(...innerRest); // 這里使用的是ES6數組的解構 return _adder; }; _adder.toString = function () { let sum = _args.reduce(function (a, b) { return a + b; }); return sum; }; return _adder; } console.log(sumWithES6(1)(2)(3)); // 6 ~~~ # 先指定參數個數 ~~~ function total(argNum) { return function sum() { var args = Array.from(arguments) var restArgs = argNum - args.length var that = this if (restArgs) { return function () { return sum.apply(that, args.concat(Array.from(arguments))) } } else { return args.reduce((cur, next) => { return cur + next }, 0) } } } var two = total(2) console.log(two(1,2)) console.log(two(1)(4)) var three = total(3) console.log(three(4,5,6)) console.log(three(1,2)(5)) console.log(three(1)(4)(7)) ~~~ # 參考資料 [JS中的柯里化](https://segmentfault.com/a/1190000012769779) [詳解JS函數柯里化](https://www.jianshu.com/p/2975c25e4d71) [sum(1,2)(3)與函數柯里化](http://yimiao.space/2021/02/01/sum-1-2-3-%E4%B8%8E%E5%87%BD%E6%95%B0%E6%9F%AF%E9%87%8C%E5%8C%96/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看