# Js中Currying的应用

## 描述

`f(a,b,c) → f(a)(b)(c)`

```// 柯里化
f(a,b,c) → f(a)(b)(c)
// 部分函数调用
f(a,b,c) → f(a)(b,c) / f(a,b)(c)```

## 实现

```var add = function(x) {
return function(y) {
return x + y;
};
};

```function convertToCurry(funct, ...args) {
const argsLength = funct.length;
return function(..._args) {
_args.unshift(...args);
if (_args.length < argsLength) return convertToCurry.call(this, funct, ..._args);
return funct.apply(this, _args);
}
}

var funct = (x, y, z) => x + y + z;
console.log(result); // 6```

```function convertToCurry(funct, ...args) {
const argsLength = funct.length;
return function(..._args) {
_args.unshift(...args);
if (_args.length < argsLength) return convertToCurry.call(this, funct, ..._args);
return funct.apply(this, _args);
}
}

var check = (regex, str) =>  regex.test(str);
var checkPhone = convertToCurry(check, /^1[34578]\d{9}\$/);
var checkEmail = convertToCurry(check, /^(\w)+(\.\w+)*@(\w)+((\.\w+)+)\$/);
console.log(checkPhone("13300000000")); // true
console.log(checkPhone("13311111111")); // true
console.log(checkPhone("13322222222")); // true
console.log(checkEmail("13300000000@a.com")); // true
console.log(checkEmail("13311111111@a.com")); // true
console.log(checkEmail("13322222222@a.com")); // true```

## 应用

```// 假设一个延时函数需要传递一些参数
// 通常使用的版本如下
var delayAsync = function(time, callback, ...args){
setTimeout(() => callback(...args), time);
}

var callback = function(x, y, z){
console.log(x, y, z);
}

delayAsync(1000, callback, 1, 2, 3);

// 使用Thunk函数

var thunk = function(time, ...args){
return function(callback){
setTimeout(() => callback(...args), time);
}
}

var callback = function(x, y, z){
console.log(x, y, z);
}

var delayAsyncThunk = thunk(1000, 1, 2, 3);
delayAsyncThunk(callback);```

```var convertToThunk = function(funct){
return function (...args){
return function (callback){
return funct.apply(this, args);
}
};
};

var callback = function(x, y, z){
console.log(x, y, z);
}

var delayAsyncThunk = convertToThunk(function(time, ...args){
setTimeout(() => callback(...args), time);
});

thunkFunct = delayAsyncThunk(1000, 1, 2, 3);
thunkFunct(callback);```

`Thunk`函数在`ES6`之前可能应用比较少，但是在`ES6`之后，出现了`Generator`函数，通过使用`Thunk`函数就可以可以用于`Generator`函数的自动流程管理。首先是关于`Generator`函数的基本使用，调用一个生成器函数并不会马上执行它里面的语句，而是返回一个这个生成器的迭代器`iterator`对象，他是一个指向内部状态对象的指针。当这个迭代器的`next()`方法被首次（后续）调用时，其内的语句会执行到第一个（后续）出现`yield`的位置为止，`yield`后紧跟迭代器要返回的值，也就是指针就会从函数头部或者上一次停下来的地方开始执行到下一个`yield`。或者如果用的是`yield*`，则表示将执行权移交给另一个生成器函数（当前生成器暂停执行）。

```function* f(x) {
yield x + 10;
yield x + 20;
return x + 30;
}
var g = f(1);
console.log(g); // f {<suspended>}
console.log(g.next()); // {value: 11, done: false}
console.log(g.next()); // {value: 21, done: false}
console.log(g.next()); // {value: 31, done: true}
console.log(g.next()); // {value: undefined, done: true} // 可以无限next()，但是value总为undefined，done总为true```

```var it = null;

function f(){
var rand = Math.random() * 2;
setTimeout(function(){
if(it) it.next(rand);
},1000)
}

function* g(){
var r1 = yield f();
console.log(r1);
var r2 = yield f();
console.log(r2);
var r3 = yield f();
console.log(r3);
}

it = g();
it.next();```

```function thunkFunct(index){
return function f(funct){
var rand = Math.random() * 2;
setTimeout(() => funct({rand:rand, index: index}), 1000)
}
}

function* g(){
var r1 = yield thunkFunct(1);
console.log(r1.index, r1.rand);
var r2 = yield thunkFunct(2);
console.log(r2.index, r2.rand);
var r3 = yield thunkFunct(3);
console.log(r3.index, r3.rand);
}

function run(generator){
var g = generator();

var next = function(data){
var res = g.next(data);
if(res.done) return ;
// console.log(res.value);
res.value(next);
}

next();
}

run(g);```

## 每日一题

`https://github.com/WindrunnerMax/EveryDay`

## 参考

```https://www.jianshu.com/p/5e1899fe7d6b
https://zhuanlan.zhihu.com/p/108594470
https://blog.csdn.net/crazypokerk_/article/details/97674338
http://www.qiutianaimeili.com/html/page/2019/05/54g0vvxycyg.html

0 条评论

• ### Thunk函数的使用

编译器的求值策略通常分为传值调用以及传名调用，Thunk函数是应用于编译器的传名调用实现，往往是将参数放到一个临时函数之中，再将这个临时函数传入函数体，这个临时...

• ### JavaScript变量提升

在JavaScript中变量声明与函数声明都会被提升到作用域顶部，优先级依次为：变量声明 函数声明 变量赋值

• ### Vue中数组变动监听

Vue的通过数据劫持的方式实现数据的双向绑定，即使用Object.defineProperty()来实现对属性的劫持，但是Object.defineProper...

• ### 浅谈JavaScript的函数表达式（闭包）

前文已经简单的介绍了函数的闭包。函数的闭包就是有权访问另一个函数作用域的函数，也就是函数内部又定义了一个函数。 1 var Super=function(n...

• ### 从零开始学 Web 之 JavaScript（三）函数

全局变量：在 script 使用 var 定义的变量（所有的 script 共享其全局性，js 里面没有块级作用域概念，只有全局作用域和局部作用域）。

• ### 高阶函数和闭包

函数也是一种数据类型，同样可以作为参数，传递给另外一个参数使用。最典型的就是作为回调函数。

• ### JavaScript解析机制之变量提升

在当前作用域下，JS 运行之前，会把带有 var 和 function 关键字的事先声明，并在内存中安排好。（这个过程也可以理解为变量提升）然后再从上到下执行 ...

• ### 前端必备，25个最基本的JavaScript面试问题及答案

1.使用 typeof bar === "object" 来确定 bar 是否是对象的潜在陷阱是什么？如何避免这个陷阱？