-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
编写一个通用的柯里化函数currying #33
Comments
常规法 const currying = fn => {
if (typeof fn !== 'function') {
return new Error('No function provided')
}
return function curriedFn(...args){
if (args.length < fn.length) {
return function () {
return curriedFn.apply(null, args.concat([].slice.call(arguments)))
}
}
return fn.apply(null, args)
}
} 支持多调用法 const currying = (func, count = func.length, ...args) => count <= args.length ? func(...args) : currying.bind(null, func, count, ...args)
const sum = (...args) => args.reduce((acc, cur) => acc + cur, 0)
const add = currying(sum, 2)
console.log(add(1)(2)) |
再来个左向, 自动柯里化 |
来个ES5的
|
类似 lodash 的 curry,支持占位符,支持 new 调用时忽略 thisfunction curry(func, arity = func.length, guard, partial = []) {
// guard 守卫, 防止传入多余参数
partial = guard === void 0 ? partial : []
const placeholder = curry.placeholder
const boundFunc = function(...args) {
const argsLen = args.filter(arg => arg !== placeholder).length
// _replaceHolders 函数, 处理占位符的情况
const finalArgs = _replaceHolders(partial, args, placeholder)
if (argsLen >= arity) {
// _executeBound 函数, 处理 new 调用boundFunc ,this应被忽略问题
return _executeBound(func, boundFunc, this, this, finalArgs)
} else {
return curry(func, arity - argsLen, void 0, finalArgs)
}
}
return boundFunc
}
// 设置占位符, 默认 '__'
curry.placeholder = '__'
// 整合 partials 和 args 为一个 完整的参数数组, 将partials中的 placeholder替换为 args中元素, args中剩余元素放到 数组结尾
function _replaceHolders(partials, args, placeholder) {
let separator = 0
const combinedArgs = partials.map(partial => {
if (partial === placeholder) {
return args[separator++]
}
return partial
})
return [...combinedArgs, ...args.slice(separator)]
}
function _executeBound(func, boundFunc, thisArg, context, args) {
if (!(context instanceof boundFunc)) {
return func.call(thisArg, ...args)
}
const instance = Object.create(func.prototype)
const result = func.call(instance, ...args)
if (isObject(result)) {
return result
}
return instance
}
function isObject(obj) {
const type = typeof obj
return obj !== null && (type == 'object' || type == 'function')
} |
函数柯里化是逐步传参、逐步缩小函数的适用范围、逐步求解的过程,它将多变量函数拆解为单变量的多个函数的依次调用。
函数柯里化的主要作用和特点:
|
const currying = fn => {
return function curriedFn(...args){
if (args.length < fn.length) {
return function () {
return curriedFn.apply(null, args.concat([].slice.call(arguments)))
}
}
return fn.apply(null, args)
}
} |
function curry(fn) {
let oldArgs = Array.prototype.slice.call(arguments, 1);
return function() {
let newArgs = Array.prototype.slice.call(arguments);
let args = newArgs.concat(oldArgs);
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return curry.call(this, fn, ...args);
}
}
} |
在开始之前,我们首先需要搞清楚函数柯里化的概念。 函数柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。 const currying = (fn, ...args) =>
args.length < fn.length
//参数长度不足时,重新柯里化该函数,等待接受新参数
? (...arguments) => currying(fn, ...args, ...arguments)
//参数长度满足时,执行函数
: fn(...args); function sumFn(a, b, c) {
return a + b + c;
}
var sum = currying(sumFn);
console.log(sum(2)(3)(5));//10
console.log(sum(2, 3, 5));//10
console.log(sum(2)(3, 5));//10
console.log(sum(2, 3)(5));//10 函数柯里化的主要作用:
|
函数柯里化函数柯里化,就是见一个接受多个参数的函数转化为接受单一参数的函数的技术.代码如下,亲测可用
|
柯里化函数:一个currying的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
|
|
|
什么是柯里化函数curry 的概念很简单:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。 例子:
柯里化实现1- 这里利用的是bind的this参数后面的会使一个函数拥有预设的初始参数。当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置
2- 在1的基础上限制参数的个数,比如你想要的是5个
3- 因此,除去存储参数以外,我们还需要在某处存储对于目标函数的引用
magician 函数的作用是:它接收目标函数作为参数,然后返回‘参数收集器’函数,与上例中 fn 函数作用相同。唯一的不同点在于,当收集的参数数量与目标函数所必需的参数数量相等时,它将把收集到的参数通过 apply 方法给到该目标函数,并返回计算的结果。这个方法通过将其存储在 magician 创建的闭包当中来解决第一个问题(引用目标函数)。 4- 使用magician函数本身作为参数收集器
因为magician接受目标函数作为它的第一个参数,因此收集到的参数将始终包含该函数作为arguments[0]。这就导致,我们在检查有效参数的总数时,需要减去第一个参数。 |
function progressCurrying(fn, args) {
var _this = this
var len = fn.length;
var args = args || [];
return function() {
var _args = Array.prototype.slice.call(arguments);
Array.prototype.push.apply(args, _args);
// 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
if (_args.length < len) {
return progressCurrying.call(_this, fn, _args);
}
// 参数收集完毕,则执行fn
return fn.apply(this, _args);
}
}
const sum = (...args) => args.reduce((acc, cur) => acc + cur, 0)
const add = currying(sum, 2)
console.log(add(1)(2)) |
No description provided.
The text was updated successfully, but these errors were encountered: