Skip to content

骚操作-函数柯里化

科里化函数:固定某个函数的一些参数,得到该函数剩余参数的一个新函数,如果没有剩余参数,则调用

js
/**
 * 科里化函数
 * 在函数式编程中,科里化最重要的作用是把多参函数变为单参函数
 */
this.myPlugin.curry = function (func) {
  //得到从下标1开始的参数
  var args = Array.prototype.slice.call(arguments, 1);
  var that = this;
  return function () {
    var curArgs = Array.from(arguments); //当前调用的参数
    var totalArgs = args.concat(curArgs);
    if (totalArgs.length >= func.length) {
      //参数数量够了
      return func.apply(null, totalArgs);
    } else {
      //参数数量仍然不够
      totalArgs.unshift(func);
      return that.curry.apply(that, totalArgs);
    }
  };
};

柯里化的应用场景

柯里化的应用就是为了固定函数的参数,属于函数式编程的思想,比较难理解。

js
function f(x, y, z) {
  return (x + y) * z;
}

// 求:(2+3)*5  (2+5)*6  (2+4)*7  (2+4)*16
var g = myPlugin.curry(f, 2); //固定第一个参数
console.log(g(3, 5));
console.log(g(5, 6));

var y = g(4); // 相当于var y = myPlugin.curry(f, 2, 4);
console.log(y(7));
console.log(y(16));
html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      .container {
        border: 2px solid;
        padding: 30px;
      }
    </style>
  </head>

  <body>
    <div class="container"></div>
    <script src="../../plugin/helpers.js"></script>
    <script>
      //创建一个元素,传入对应的参数
      function createElement(container, name, props, styles, content) {
        var ele = document.createElement(name);
        container.appendChild(ele);

        for (var prop in props) {
          ele[prop] = props[prop];
        }

        for (var prop in styles) {
          ele.style[prop] = styles[prop];
        }
        if (content) {
          ele.innerHTML = content;
        }
      }

    //固定响应的参数,然后简化调用
      var div = document.querySelector(".container");

      var create = myPlugin.curry(
        createElement,div,"div",{},
        {
          height: "100px",
          background: "#008c8c",
          margin: "30px",
          color: "#fff",
        }
      );

      create("asdfasdf");//所有的调用都被简化了
      create("2344");
      create("asdfa4545sdf");
      create("asdfa234324234sdf");
      create("asdfa132112313sdf");
      create("563456435634");
      create("啊打发法是发啊手动阀啊");
    </script>
  </body>
</html>

:::

骚操作-函数管道

函数管道:将多个单参函数组合起来,形成一个新的函数,这些函数中,前一个函数的输出,是后一个函数的输入

js
/**
 * 函数管道
 */
this.myPlugin.pipe = function () {
    var args = Array.from(arguments);
    return function (val) {
        return args.reduce(function (result, func) {
            return func(result);
        }, val);

        // 第二种写法
        // for (var i = 0; i < args.length; i++) {
        //     var func = args[i];
        //     val = func(val);
        // }
        // return val;

    }
}

应用场景:

js
//将字符串中每一个单词首字母大写
function everyFirstLetterUp(str) {
    return str.replace(/\b(\w)(\w*)\b/g, function($, $1, $2) {
        return $1.toUpperCase() + $2;
    });
}

//将字符串中除首字母外的其他字母小写
function otherLetterLower(str) {
    return str.replace(/\b(\w)(\w*)\b/g, function($, $1, $2) {
        return $1 + $2.toLowerCase();
    });
}

//去掉字符串中所有的空白字符
function removeEmpty(str) {
    return str.replace(/\s+/g, "");
}

//将字符串中第一个单词字符小写
function firstLetterLower(str) {
    return str.replace(/\w/, function($) {
        return $.toLowerCase();
    });
}

//截取字符串
function curString(number, str) {
    return str.substr(0, number);
}


//以上准备了很多工具函数,接下来要将字符串转变为小驼峰命名法
let  str="    MY     fIrST    naME";

// 普通写法 需要调用很多次
str=everyFirstLetterUp(str);
str=otherLetterLower(str);
str=removeEmpty(str);
str=firstLetterLower(str);
str=curString(10, str);

// 使用函数管道将流程封装即可,当遇到不是单参函数,可以使用柯里化变成单参函数
var smallCamel = myPlugin.pipe(
  everyFirstLetterUp, 
  firstLetterLower,
  otherLetterLower,
  removeEmpty, 
  myPlugin.curry(curString, 10)
);

console.log(smallCamel("    MY     fIrST    naME"));
console.log(smallCamel("  asdfasf  sdfasf   ggggggg  hGDGF"));

MIT License