forked from zzzzzhowie/practical-javascript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcurry.js
More file actions
128 lines (108 loc) · 4.28 KB
/
curry.js
File metadata and controls
128 lines (108 loc) · 4.28 KB
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/**
* @description 函数柯里化(根据柯里化前的函数的参数数量决定柯里化后的函数需要执行多少次)
* @param {function} fn -柯里化的函数
*/
function curry(fn) {
if (fn.length <= 1) return fn;
const generator = (...args) => {
if (fn.length === args.length) {
//执行fn并且返回执行结果
return fn(...args)
} else {
return (...args2) => {
//返回generator函数
return generator(...args, ...args2)
}
}
}
return generator
}
const display = (a, b, c, d, e, f, g, h) => [a, b, c, d, e, f, g, h];
const curriedDisplay = curry(display);
console.log("curriedDisplay", curriedDisplay(1)(2)(3)(4)(5)(6)(7)(8));
//ES6简写
const curry2 = fn => {
if (fn.length <= 1) return fn;
const generator = (...args) => (args.length === fn.length ? fn(...args) : (...args2) => generator(...args, ...args2));
return generator;
};
const curriedDisplay2 = curry2(display);
console.log("curriedDisplay2", curriedDisplay2(1)(2)(3)(4)(5)(6)(7)(8));
/**
* @description 函数柯里化(支持占位符版本)
* @param {function} fn -柯里化的函数
* @param {String} [placeholder = "_"] -占位符
*/
const curry3 = (fn, placeholder = "_") => {
curry3.placeholder = placeholder
if (fn.length <= 1) return fn;
let argsList = []
const generator = (...args) => {
let currentPlaceholderIndex = -1 // 记录了非当前轮最近的一个占位符下标,防止当前轮元素覆盖了当前轮的占位符
args.forEach(arg => {
let placeholderIndex = argsList.findIndex(item => item === curry3.placeholder)
if (placeholderIndex < 0) { // 如果数组中没有占位符直接往数组末尾放入一个元素
currentPlaceholderIndex = argsList.push(arg) - 1
// 防止将元素填充到当前轮参数的占位符
// (1,'_')('_',2) 数字2应该填充1后面的占位符,不能是2前面的占位符
} else if (placeholderIndex !== currentPlaceholderIndex) {
argsList[placeholderIndex] = arg
} else { // 当前元素是占位符的情况
argsList.push(arg)
}
})
let realArgsList = argsList.filter(arg => arg !== curry3.placeholder) //过滤出不含占位符的数组
if (realArgsList.length === fn.length) {
return fn(...argsList)
} else if (realArgsList.length > fn.length) {
throw new Error('超出初始函数参数最大值')
} else {
return generator
}
}
return generator
}
const curriedDisplay3 = curry3(display);
console.log("curriedDisplay3", curriedDisplay3('_', 2)(1, '_',4)(3, '_',)('_', 5)(6)(7, 8))
//函数组合+函数柯里化
const compose = function (...fns) {
return function (initValue) {
return fns.reduceRight((acc, cur) => {
return cur(acc)
}, initValue)
}
}
const curriedJoin = curry3((separator, arr) => arr.join(separator))
const curriedMap = curry3((fn, arr) => arr.map(fn))
const curriedSplit = curry3((separator, str) => str.split(separator))
const composeFunc = compose(
curriedJoin("1"),
curriedMap(item => `${item}1`),
curriedSplit(""),
)
console.log("compose + curry", composeFunc('helloworld'))
/**
* @description 偏函数(创建已经设置好一个或多个参数的函数,并且添加了占位符功能)
* @param {Function} func -部分求值的函数
* @param {...*} [args] -部分求值的参数
* @return {Function} -部分求值后的函数
**/
const partialFunc = (func, ...args) => {
let placeholderNum = 0
return (...args2) => {
args2.forEach(arg => {
let index = args.findIndex(item => item === "_")
if (index < 0) return
args[index] = arg
placeholderNum++
})
if (placeholderNum < args2.length) {
args2 = args2.slice(placeholderNum, args2.length)
}
return func.apply(this, [...args, ...args2])
}
}
let partialDisplay = partialFunc(display, 1, 2)
console.log("partialFunc", partialDisplay(3, 4, 5, 6, 7, 8))
let partialDisplay2 = partialFunc(display, '_', 2, '_')
console.log('partialFunc2', partialDisplay2(1, 3, 4, 5, 6, 7, 8))