# 函数柯里化&偏函数

## 举个例子

### 先举一个普通函数

``````let dragon = (name, size, element) => {
return `\${name} is a \${size} dragon that breathes \${element}!`;
};

console.log(dragon("Karo", "large", "ice"));
// Karo is a large dragon that breathes ice!

### 模拟柯里化方式

``````let dragon = name => size => element =>
`\${name} is a \${size} dragon that breathes \${element}!`;
console.log(dragon('Karo')('large')('ice'));
// Karo is a large dragon that breathes ice!

## 高程中柯里化的实现方式

``````function curry(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(null, finalArgs);
}
}

let dragon = (name, size, element) => {
return `\${name} is a \${size} dragon that breathes \${element}!`;
};
dragon = curry(dragon);
let fluffykinsDragon = dragon('fluffykins'); // curyy函数只能保存一个参数就返回了
// fluffykins is a undefined dragon that breathes undefined!
// 如果执行下面语句就会报错，
// let tinyDragon = fluffykinsDragon("tiny"); 报错

## 柯里化函数如何实现呢？

### 柯里化第一版

``````// 第一版
function curry(fn) {
var args = [];
return function() {
args = args.concat([].slice.call(arguments));
return function() {
args = args.concat([].slice.call(arguments));
return function() {
args = args.concat([].slice.call(arguments));
return fn.apply(null, args);
}
}
};
}

``````// 测试
let dragon = (name, size, element) => {
return `\${name} is a \${size} dragon that breathes \${element}!`;
};
dragon = curry(dragon);
let fluffykinsDragon = dragon("fluffykins");
let tinyDragon = fluffykinsDragon("tiny");
console.log(tinyDragon("ice"));
// fluffykins is a tiny dragon that breathes ice!

### 柯里化第二版

``````// 第二版
function curry(fn, args, length) {
length = length || fn.length;
args = args || [];
return function() {
args = args.concat([].slice.call(arguments));
if (arguments.length < length) {
return curry(fn, args, length - arguments.length);
}
return fn.apply(this, args);
}
}

### 柯里化第三版

``````// 第三版
function sub_curry(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(null, finalArgs);
}
}

function curry(fn, length) {
length = length || fn.length;
return function() {
if (arguments.length < length) {
var args = [fn].concat([].slice.call(arguments));
return curry(sub_curry.apply(this, args), length - arguments.length);
}
return fn.apply(this, arguments);
};
}

### 使用ES6改写一下，优化一下

``````function sub_curry(fn, ...args) {
return (...args1) => fn(...args, ...args1);
}

function curry(fn, length) {
length = length || fn.length;
return (...args) => {
if (args.length < length) {
return curry(sub_curry(fn, ...args), length - args.length);
}
return fn(...args);
};
}

### 穿插一下1

``````function curry(fn, args) {
var length = fn.length;

args = args || [];
return function() {
var _args = args.concat([].slice.call(arguments));
if (_args.length < length) {
return curry.call(this, fn, _args);
}
return fn.apply(this, _args);
};
}

### 穿插一下2——我看到一种更简洁的写法

``````function curry(fn) {
return judge = (...args) => {
return args.length === fn.length ? fn(...args) : (...arg) => judge(...args, ...arg);
};
}

### 柯里化第四版

``````// 第四版
function curry(fn, args) {
var length = fn.length;
args = args || [];
return function() {
var newArgs = [].slice.call(arguments);
for (var i = 0, len = args.length; i < len; i++) {
if (args[i] === _) {
args.splice(i, 1, newArgs.shift());
}
if (newArgs.length === 0) break;
}
var _args = args.concat(newArgs);
var _filterArr = _args.filter(ele => ele !== _);
if (_filterArr.length < length) {
return curry.call(this, fn, _args);
}
return fn.apply(this, _args);
};
}

``````var fn = curry(function(a, b, c, d, e) {
console.log([a, b, c, d, e]);
});
var _ = {};
// 输出的结果都是[1, 2, 3, 4, 5]
fn(1, 2, 3, 4, 5);
fn(_, 2, 3, 4, 5)(1);
fn(1, _, 3, 4, 5)(2);
fn(1, _, 3)(_, 4)(2)(5);
fn(1, _, _, 4)(_, 3)(2)(5);
fn(_, 2)(_, _, 4)(1)(3)(5);

## 偏函数第一版

``````// 也就是高程中的例子
function partial(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(null, finalArgs);
}
}

## 偏函数第二版

``````var _ = {};
function partial(fn) {
var args = [].slice.call(arguments, 1);
return function() {
var len = args.length;
var _args = [].slice.call(arguments);
for(var i = 0; i < len; i++) {
args[i] = args[i] === _ ? _args.shift() : args[i];
if (_args.length === 0) break;
}
args.concat(_args);
return fn.apply(this, args);
}
}

``````var subtract = function(a, b, c) {
return b - a + c;
};
var subFrom20 = partial(subtract, 5, _, _);
console.log(subFrom20(15, 5, 5)); // 15

Tony's blog

• 布衣1983
10小时前
• Cosolar
4天前
• PuffMeow
1天前
• 泯泷
23小时前
• 布衣1983
1天前
• 强生
5天前
• tonytony
1月前