柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

主要应用:

1. 参数复用

  1. // 拼接URL,复用“protocol”参数
  2. function url(protocol){
  3. return function(host){
  4. return `${protocol}${host}`
  5. }
  6. }
  7. const httpUrl = url("http://")
  8. const httpsUrl = url("https://")
  9. console.log(httpUrl("192.168.0.2")) // http://192.168.0.2
  10. console.log(httpsUrl("192.168.0.2")) // https://192.168.0.2

2. 提前确认(避免每次都重复调用)

  1. // dom事件的兼容性处理
  2. // 提前执行这个函数,不用每次执行都会去进行判断
  3. const addEvent = (function () {
  4. // 高版本浏览器
  5. if (document.addEventListener) {
  6. return function (element, event, handler) {
  7. if (element && event && handler) {
  8. element.addEventListener(event, handler, false);
  9. }
  10. }
  11. } else { // ie浏览器
  12. return function (element, event, handler) {
  13. if (element && event && handler) {
  14. element.attachEvent('on' + event, handler);
  15. }
  16. };
  17. }
  18. })()

3. 延迟运行

  • 封装函数的bind方法
    1. // context是_bind想要改变的this指向
    2. Function.prototype._bind = function (context) {
    3. let fn = this // 调用_bind的对象
    4. // 返回一个新函数,延迟执行 apply方法
    5. return function (...args) {
    6. fn.apply(context, args)
    7. }
    8. }

    经典面试题:add(1)(2)(3)

    ```javascript function add() { let args = […arguments] return function childAdd() { if (arguments.length != 0) { // 判断传入的参数是否是空,不为空就递归
    1. args.push(...arguments)
    2. return childAdd
    } return args.reduce((pre, item) => pre + item, 0) 参数为空就返回所有参数的值 } } console.log(add(1, 2)(4)(5)())

// 此题可以网上大多数解法是修改函数的toString方法,但node执行没有效果,浏览器也并非所有都兼容 // 附:toString解法 function add() { let args = […arguments] return function childAdd() { args.push(…arguments) childAdd.toString = function () { return args.reduce((pre, item) => pre + item, 0) } return childAdd } } console.log(add(1, 2)(4)(5))

  1. <a name="iItRO"></a>
  2. ## 封装让函数柯里化的方法
  3. ```javascript
  4. // 封装柯里化函数
  5. function curring(fn, ...args) {
  6. let that = this // 保存调用curring函数的this
  7. return function cur() {
  8. // 收集参数,将首次调用curring传入的参数和这次的参数合并
  9. let _arg = args.concat(Array.from(arguments))
  10. if (_arg.length < fn.length) { // 没有集齐参数,继续收集
  11. let a = Array.from(arguments) // 保存本次传入的参数
  12. return function () {
  13. // 把上一次传入的参数和这一次的合并
  14. return cur.apply(that, a.concat(Array.from(arguments)))
  15. }
  16. }
  17. return fn.apply(that, _arg) // 集齐参数,执行该函数
  18. }
  19. }
  20. // 测试代码
  21. function sum(a, b, c) {
  22. return a + b + c
  23. }
  24. let fn1 = curring(sum, "jj")
  25. let fn2 = curring(sum)("kkk")
  26. let fn3 = curring(sum)("ccc")('ff')
  27. console.log(fn1(2, 3)) // jj23
  28. console.log(fn1(5)(4)) // jj54
  29. console.log(fn2(2, 3)) // kkk23
  30. console.log(fn2(3)(4)) //kkk34
  31. console.log(fn3(3)) //cccff3
  32. console.log(fn3(4)) // cccff4