函数柯里化
Jonnzer Lv4

1. 是什么?

柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的编程技术。
简单示例:

1
2
3
4
5
6
7
8
9
function add(a, b) { return a + b; }

// 执行 add 函数,一次传入两个参数即可
add(1, 2) // 3

// 假设有一个 curry 函数可以做到柯里化
var addCurry = curry(add);

addCurry(1)(2) // 调用跟 add (1,2)是一样的

2. curry函数的编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
@feature 普通curry函数的编写
arguments 对象是内部函数的。
当调用(返回的函数)时,它会在给定环境中执行被传入的函数并给出所有参数。
arguments会视为每次传的参数而定
*
*/
function curry(fn, args) {
var length = fn.length;
args = args || []; // 直到这个时候的arguments都是类数组,arguments[0] = function(a,b,c)
return function() {
var _args = args.slice(0),
arg, i;
for (i = 0; i < arguments.length; i++) {
arg = arguments[i];
_args.push(arg);
}
if (_args.length < length) { // 这个if else是关键,让curry函数一直循环到,实参数满足形参的个数
console.log(this)
return curry.call(this, fn, _args);
}
else {
return fn.apply(this, _args);
}
}
}

var fn = curry(function(a, b, c) {
console.log([a, b, c]);
});

fn("a", "b", "c")
fn("a", "b")("c")
fn("a")("b")("c")
fn("a")("b", "c")

// 上面四种都会得出这样的结果: ["a", "b", "c"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 提前返回的例子
var addEvent = (function() {
if(window.addEventListener) {
return function(el, type, fn, capture) { // 提前返回
el.addEventListener(type, function(e) {
fn.call(el, e);
}, capture);
}
}else {
return function(ele, type, fn) { // 提前返回
el.attachEvent('on' + type, function(e) {
fn.call(el, e);
})
}
}
})()

3. curry函数写法的引申思考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 简易版,理解 fn1 中 return fn2的执行
function testFn() {
for (let i = 0; i < 3; i++ ) {
console.log(i)
}
return function () {
return 123
}
}
var k = testFn()
console.log(k())
console.log(k())
console.log(k())
// k函数表达式的执行,仅仅只有第一次会执行testFn里的for循环,其他次数都已经解析成里面return 123 的函数了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// vue 识别html标签的函数
function makeMap(tagStr) {
const tagArr = tagStr.split(',');
const tagObj = {};
for (const tag of tagArr) {
tagObj[tag] = true;
}
return function (tagName) { // 此处还运用了闭包去存储tagObj,仅运行一次就缓存好tagObj,降低了遍历带来的性能消耗
return !!tagObj[tagName];
}
}

const isHTMLTag = makeMap('div,p,span,h1');
console.log(isHTMLTag('div')); // true

4. curry函数的特点与作用

  • 参数复用,提前固定参数
  • 提前返回

参考文章:
javascript.Info
冴羽github文章
argumentsfunction.length的区别
Function.length
github闭包论坛

  • 本文标题:函数柯里化
  • 本文作者:Jonnzer
  • 创建时间:2020-05-27 15:12:29
  • 本文链接:https://jonnzer.github.io/2020/05/27/函数柯里化/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论