-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
JavaScript专题之函数柯里化 #42
Comments
日常学习 |
好难理解啊 |
segmentfault 的@大笑平 补充的高颜值写法: var curry = fn =>
judge = (...args) =>
args.length === fn.length
? fn(...args)
: (arg) => judge(...args, arg) |
专题系列专不知不觉更新了这么多,我得好好抽个时间系统学习一下😂 |
@jawil 哈哈~ 还有五篇就要完结了,可以等完结后一起看~ |
没有说道 什么场景下使用 柯里化 |
var name = person.map(function (item) {
return item.name;
})
const fn = function (item) {
return item.name;
}
person.map(fn) PS:这样也可以参数复用 |
@yangchongduo 柯里化的应用更多在函数式编程中,可以看 JS 函数式编程指南,在 《JavaScript专题之函数组合》这篇文章中也有涉及部分。 |
@yangchongduo 这样确实可以做到参数复用,其实跟 var name = person.map(prop('name')) 是一样的,不过如果我们要获得其他属性呢?比如 'age'、'friends' 等,如果使用 fn 的话,还需要写多个 fn,而如果使用 prop 函数,就可以直接使用 prop('age') prop('friend') |
高颜值写法的 |
function curry1(fn, args) { |
值得一看~ |
深受启发,这样理解柯里化 :用闭包把参数保存起来,当参数的数量足够执行函数了,就开始执行函数,有没有毛病 |
@hlmjack 正是如此~ o( ̄▽ ̄)d |
在更易懂的写法里 |
@fi3ework 之所以写成 this 是因为希望根据环境的不同而设置不同的 this 值,我写了一个示例: function curry(fn, args) {
var length = fn.length;
args = args || [];
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) {
return curry.call(this, fn, _args);
}
else {
return fn.apply(this, _args);
}
}
}
var fn = curry(function(a, b, c) {
console.log(this)
});
var obj = {
value: 1,
fn: fn
}
obj.fn(1, 2, 3); 这个时候的 this 的值为 obj 对象,如果设置成 null ,就会变成打印 window 对象 |
终于理解这句话了,“用闭包把参数保存起来,当参数的数量足够执行函数了,就开始执行函数” |
我有个问题想请教下。 |
@bepromising fn('a', 'b', 'c', 'd')('a') 是因为 fn('a', 'b', 'c', 'd') 就已经执行了该函数,该函数如果没有再返回一个函数,就肯定报错,说这并不是一个函数。 至于 fn('a', 'b',...n个参数)('a'),我不清楚为什么还要再传个 'a' 呢? |
柯里化 是真的绕啊 |
@BugHshine 是这篇写得不好,日后修订时会重写 |
第三版的代码是不是有bug呢,我试了一个稍微长一点的例子: var _ = {}
var ary = curry(function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z) {
return [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z]
})
console.log(ary(1,_,_)(_)(5,6,7,8,9,10)(11,12,13,14)(15,_,_,18,_)(20,21,22,_)(24,25,26)(2,3,4)(16)(17,19)(23)) 结果输出是不对的,node下: [Function] chrome下: ƒ () {
var _args = args.slice(0),
_holes = holes.slice(0),
argsLen = args.length,
holesLen = holes.length,
a… 顺便我自己用es6写了一个稍微简洁一点的,对应原文第三版,可能参数多的情况下性能会有问题,但感觉一般情况下更好理解一些 // hole为自己的指定占位符
function curry(fn, hole) {
const __len = fn.length
let args = [],
return function h() {
// 先把参数放入args数组
args = [...args, ...Array.from(arguments)]
// 如果长度超过原有函数参数列表长度,表示有占位
let holeNum = args.length - __len
// 第一个占位符对应的肯定是__len位置的变量,循环将所有占位符替换
for (let i = 0; i < holeNum; i++) {
args[args.indexOf(hole)] = args[__len]
args.splice(__len, 1)
}
// 如果没有占位符且参数数目已经够了
if (args.length < __len || args.indexOf(hole) > -1) {
return h
} else {
return fn.apply(null, args)
}
}
} 经测试上面的例子可以输出正确的结果 |
@izuomeng 这个是最终的版本吗?我这边有报错 <!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script>
// hole为自己的指定占位符
function curry(fn, hole) {
const __len = fn.length
let args = [];
return function h() {
// 先把参数放入args数组
args = [...args, ...Array.from(arguments)]
// 如果长度超过原有函数参数列表长度,表示有占位
let holeNum = args.length - __len
// 第一个占位符对应的肯定是__len位置的变量,循环将所有占位符替换
for (let i = 0; i < holeNum; i++) {
args[args.indexOf(hole)] = args[__len]
args.splice(__len, 1)
}
// 如果没有占位符且参数数目已经够了
if (args.length < __len || args.indexOf(hole) > -1) {
return h
} else {
return fn.apply(null, args)
}
}
}
var _ = {};
var fn = curry(function(a, b, c, d, e) {
console.log([a, b, c, d, e]);
});
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)
</script>
</body>
</html> |
少了一行,抱歉😄 // hole为传入的占位符
function curry(fn, hole) {
const __len = fn.length
let args = [];
return function h() {
// 先把参数放入args数组
args = [...args, ...Array.from(arguments)]
// 如果长度超过原有函数参数列表长度,表示有占位
let holeNum = args.length - __len
// 第一个占位符对应的肯定是__len位置的变量,循环将所有占位符替换
for (let i = 0; i < holeNum; i++) {
args[args.indexOf(hole)] = args[__len]
args.splice(__len, 1)
}
// 如果没有占位符且参数数目已经够了
if (args.length < __len || args.indexOf(hole) > -1) {
return h
} else {
fn.apply(null, args)
return args = []
}
}
} |
参数 |
这儿稍有点问题,当 args.length < fn.length 的时候应该使用拓展运算符 (...arg) => judge(...args, ...arg) |
|
这个实现会污染全局作用域,多次调用curry函数会有问题,比如最后实战的例子。 |
这里的this指向处理作用是什么呢 |
function curry(fn, args) {
var length = fn.length;
args = args || [];
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) {
return curry.call(this, fn, _args);
} else {
return fn.apply(this, _args);
}
};
}
var fn = curry(function (a, b, c) {
console.log(this);
});
var obj = {
value: 1,
fn: fn,
};
const result = obj.fn(1);
result(2, 3); 如果此时这样书写的话,那么this其实作用也不是很大吧 |
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length && !args.slice(0, fn.length).includes(_)) {
return fn.apply(this, args);
} else {
return function (...newArgs) {
args = args.map((arg) =>
arg === _ && newArgs.length ? newArgs.shift() : arg
);
return curried.call(this, ...args, ...newArgs);
};
}
};
}
var _ = {}; |
var curryWithPlaceholder = (fn) =>
(judge = (...args) => {
const validArgs = args.filter((i) => i !== _);
// 已获取全部有效参数
if (validArgs.length === fn.length) {
return fn(...validArgs);
} else {
return (...arg) => {
// 对旧参数的占位符进行替换,每替换一次,新参数就少一个,最后拼接剩下的新参数
args = args.map(i => i === _ && arg.length ? arg.shift() : i);
return judge(...args, ...arg);
};
}
}); |
function curry<T>(fn: Function): Function {
return function (...args: T[]) {
if (args.length < fn.length) {
return curry(fn.bind(this, ...args))
} else {
return fn(...args)
}
}
}
type IPerson = {
name: string
age: number
}
const person: IPerson[] = [
{ name: "zhangsan", age: 12 },
{ name: "lisi", age: 100 },
]
let prop = curry((key: keyof IPerson, obj: IPerson) => {
return obj[key]
}) |
function curry(fn) {
return function f(...args) {
return args.length < fn.length
? (..._args) => f(...args, ..._args) // 长度不够,等待下一次补齐
: fn(...args) // 执行函数
};
}
// call / apply
function curry(fn, args = []) {
return function () {
// 将之前的参数,和新传入的参数合并
const _args = [...args, ...arguments];
// 参数长度不够,等待下一次调用补齐
if (_args.length < fn.length) {
return curry.call(this, fn, _args);
}
// 执行函数
return fn(..._args);
};
} |
function curry (fn) {
const len = fn.length;
const args = Array.prototype.slice.call(arguments, 1);
let context = this;
function inner () {
args.push.apply(args, arguments);
if (args.length > len) {
throw new Error('curried function with ' + len + ' argument but pass ' + args.length + ' arguments')
}
if (args.length === len) {
return fn.apply(context, args)
}
return inner;
}
return inner
} 这样更容易理解 |
极简版的 curry 分析过程不能按照文中的逻辑。。。我分析了半天都对不上 fn_1 = function() {
return fn0();
}
curry(fn_1, --length)
// 也就是
function() {
if(length > 1) {
return curry(sub_curry(fn_1), --length)
}else {
return fn_1();
}
}
// 此时的 length 为 3 fn1()() 的返回值: fn_2 = function() {
return fn_1();
}
function() {
if(length > 1) {
return curry(sub_curry(fn_2), --length)
}else {
return fn_2();
}
}
// 此时的 length 为 2 fn1()()() 的返回值: fn_3 = function() {
return fn_2();
}
function() {
if(length > 1) {
return curry(sub_curry(fn_3), --length)
}else {
return fn_3();
}
}
// 此时的 length 为 1 fn1()()()() 的返回值: (function() {
if(length > 1) {
return curry(sub_curry(fn_3), --length)
}else {
return fn_3();
}
})()
fn_3()
fn_2()
fn_1()
fn0()
console.log(1) |
fn(1, _, , 4)(, 3)(2)(5)的结果为何不是1,3,2,4,5 |
var currying = (fn, ...arg) => (...arg.length >= fn.length ? fn(...arg) : (..._arg) => currying(fn, ...arg, ..._arg)) |
你是 (_,3) ,3前面还有个占位符,所以2会到3前面 |
很精简,稍微改下会更强大,
|
掘金 的这篇文章写出来的代码比较好理解: /**
* @param {*} fn 回调函数
* @param {*} [length=fn.length] 回调函数所需要参数的数量
* @param {*} [holder=curry] 占位符
*/
function curry(fn, length = fn.length, holder = curry) {
return _curry.call(this, fn, length, holder, [], [])
}
/**
*
* @param {*} fn 回调函数
* @param {*} length 回调函数参数的长度
* @param {*} holder 占位符
* @param {*} args 接收参数数组
* @param {*} holders 占位符数组
* @return {*}
*/
function _curry(fn, length, holder, args, holders) {
return function (..._args) {
let params = args.slice()
// 代表这次的占位符数组
let _holders = holders.slice()
_args.forEach((arg, i) => {
// 不存在占位符且占位符有记录
if (arg !== holder && holders.length) {
let index = holders.shift()
_holders.splice(_holders.indexOf(index), 1)
params[index] = arg
}
// 不存在占位符且占位符没有记录
else if (arg !== holder && !holders.length) {
params.push(arg)
}
// 存在占位符且占位符没有记录
else if (arg === holder && !holders.length) {
params.push(arg)
_holders.push(params.length - 1)
}
// 存在占位符且占位符有记录
else if (arg === holder && holders.length) {
holders.shift()
}
})
// params 中没有占位符才能执行函数
if (params.length >= length && params.slice(0, length).every((i) => i !== holder)) {
return fn.apply(this, params)
} else {
return _curry.call(this, fn, length, holder, params, _holders)
}
}
}
let fn = function (a, b, c, d, e) {
console.log([a, b, c, d, e])
}
let _ = {} // 定义占位符
let _fn = curry(fn, 5, _) // 将函数柯里化,指定所需的参数个数,指定所需的占位符
_fn(1, 2, 3, 4, 5) // print: 1,2,3,4,5
_fn(_, 2, 3, 4, 5)(1) // print: 1,2,3,4,5
_fn(1, _, 3, 4, 5)(2) // print: 1,2,3,4,5
_fn(1, _, 3)(_, 4, _)(2)(5) // print: 1,2,3,4,5
_fn(1, _, _, 4)(_, 3)(2)(5) // print: 1,2,3,4,5
_fn(_, 2)(_, _, 4)(1)(3)(5) // print: 1,2,3,4,5 |
function.length是形参的个数,如果参数数量未知呢 |
好问题 你需要注意到 js 函数是不在乎参数数量的多少的 所以 你传入多少参数 length都能正常工作<br/><br/><br/><html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<div id="imail_signature" class="ntes-signature"> <a href="https://maas.mail.163.com/dashi-web-extend/html/proSignature.html?ftlId=1&name=a2742217795%40hotmail.com&uid=a2742217795%40hotmail.com&iconUrl=https%3A%2F%2Fmail-online.nosdn.127.net%2Fqiyelogo%2FdefaultAvatar.png&items=%5B%22%E9%82%AE%E7%AE%B1%EF%BC%9Aa2742217795%40hotmail.com%22%5D" style="display:block;background:#fff; max-width: 400px; _width: 400px;padding:15px 0 10px 0;text-decoration: none; outline:none;-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:none !important;text-size-adjust:none !important;">
<table cellpadding="0" style='width: 100%; max-width: 100%; table-layout: fixed; border-collapse: collapse;color: #9b9ea1;font-size: 14px;line-height:1.3;-webkit-text-size-adjust:none !important;text-size-adjust:none !important;'>
<tbody style="font-family: 'PingFang SC', 'Hiragino Sans GB','WenQuanYi Micro Hei', 'Microsoft Yahei', '微软雅黑', verdana !important; word-wrap:break-word; word-break:break-all;-webkit-text-size-adjust:none !important;text-size-adjust:none !important;">
<tr>
<td width="38" style="padding:0; box-sizing: border-box; width: 38px;">
<img width="38" height="38" style="vertical-align:middle; width: 38px; height: 38px; border-radius:50%;" src="https://mail-online.nosdn.127.net/qiyelogo/defaultAvatar.png" />
</td>
<td style='padding: 0 0 0 10px; color: #31353b;'>
<div style="font-size: 16px;font-weight:bold; width:100%; white-space: nowrap; overflow:hidden;text-overflow: ***@***.***</div>
</td>
</tr>
<tr width="100%" style="font-size: 14px !important; width: 100%;">
<td colspan='2' style="padding:10px 0 0 0; font-size:14px !important; width: 100%;">
<div style="width: 100%;font-size: 14px ***@***.***</div>
</td>
</tr>
</tbody>
</table>
</a></div><br/><br/><br/><div class="ntes-mailmaster-quote" style="padding-top: 1px; padding-bottom: 1px" >
<div style=" margin-top: 20px; margin-bottom: 12px; font-size: 14px; line-height: 1.25; color: #89898c; " >---- 回复的原邮件 ----</div>
<div style=" margin-bottom: 12px; font-size: 13px; line-height: 1.25; color: #2c2c2e; padding: 2px; border-radius: 8px; background-color: #f0f0f0; " >
<table width="100%" cellpadding="0" cellspacing="10" border="0">
<tr>
<td valign="top" style=" width: 4em; font-size: 13px; line-height: 1.25; color: #89898c; white-space: nowrap; " >发件人</td>
<td valign="top" style=" font-size: 13px; line-height: 1.25; color: #2c2c2e; word-break: break-all; " ><a class="mail-from" style="color: #1c83eb; text-decoration: none" ***@***.***" ***@***.***></a></td>
</tr>
<tr>
<td valign="top" style=" width: 4em; font-size: 13px; line-height: 1.25; color: #89898c; white-space: nowrap; " >日期</td>
<td class="mail-date" valign="top" style=" font-size: 13px; line-height: 1.25; color: #2c2c2e; word-break: break-all; " >2022年09月22日 17:28</td>
</tr>
<tr style="">
<td valign="top" style=" width: 4em; font-size: 13px; line-height: 1.25; color: #89898c; " >收件人</td>
<td valign="top" style=" font-size: 13px; line-height: 1.25; color: #2c2c2e; word-break: break-all; " ><a class="mail-to" style="color: #1c83eb; text-decoration: none" ***@***.***" ***@***.***></a></td>
</tr>
<tr style="">
<td valign="top" style=" width: 4em; font-size: 13px; line-height: 1.25; color: #89898c; " >抄送至</td>
<td valign="top" style=" font-size: 13px; line-height: 1.25; color: #2c2c2e; word-break: break-all; " ><a class="mail-cc" style="color: #1c83eb; text-decoration: none" ***@***.***" ***@***.***></a>、<a class="mail-cc" style="color: #1c83eb; text-decoration: none" ***@***.***" ***@***.***></a></td>
</tr>
<tr>
<td valign="top" style=" width: 4em; font-size: 13px; line-height: 1.25; color: #89898c; " >主题</td>
<td class="mail-subject" valign="top" style=" font-size: 13px; line-height: 1.25; color: #2c2c2e; word-break: break-all; " >Re: [mqyqingfeng/Blog] JavaScript专题之函数柯里化 (#42)</td>
</tr>
</table>
</div>
<div><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><p></p>
<p dir="auto">function.length是形参的个数,如果参数数量未知呢</p>
<p style="font-size:small;-webkit-text-size-adjust:none;color:#666;">—<br>Reply to this email directly, <a href="#42 (comment)">view it on GitHub</a>, or <a href="https://github.com/notifications/unsubscribe-auth/APGVUW76U3MCMTLKSFSQXETV7QREPANCNFSM4DWQVFDQ">unsubscribe</a>.<br>You are receiving this because you commented.<img src="https://github.com/notifications/beacon/APGVUWZBCSR6FKC6EGM5J7TV7QREPA5CNFSM4DWQVFD2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOJLFDOLY.gif" height="1" width="1" alt=""><span style="color: transparent; font-size: 0; display: none; visibility: hidden; overflow: hidden; opacity: 0; width: 0; height: 0; max-width: 0; max-height: 0; mso-hide: all">Message ID: <span><mqyqingfeng/Blog/issues/42/1254766383</span><span>@</span><span>github</span><span>.</span><span>com></span></span></p>
<script type="application/ld+json">[
{
***@***.***": "http://schema.org",
***@***.***": "EmailMessage",
"potentialAction": {
***@***.***": "ViewAction",
"target": "#42 (comment)",
"url": "#42 (comment)",
"name": "View Issue"
},
"description": "View this Issue on GitHub",
"publisher": {
***@***.***": "Organization",
"name": "GitHub",
"url": "https://github.com"
}
}
]</script></div>
</div>
</body>
</html>
|
这里 写成obj.fn(1, 2)(3),this指向的还是obj么? |
我是这么理解第二种写法的,就像理解递归函数一样。 function sub_curry(fn) {
const args = [].slice.call(arguments, 1)// fn之外的参数
// 返回 记住之前传入参数的闭包
return function () {
return fn.apply(this, args.concat([].slice.call(arguments)))
}
}
function curry(fn, length) {
length = length || fn.length
const slice = Array.prototype.slice
// curry的作用,返回闭包
return function () {
// 不满足出口条件,返回闭包
if (arguments.length < length) {
const combined = [fn].concat(slice.call(arguments))
// 调用sub_curry是希望得到一个能缓存argument的函数,还要改一下出口条件,只要传入length - arguments.length 个参数,就能满足出口条件
return curry(sub_curry.apply(this, combined), length - arguments.length)
} else {
// 满足出口条件后,返回fn执行结果
return fn.apply(this, arguments)
}
}
}
// 明确curry函数的作用:
// 1、返回闭包函数
// 2、确定进入出口的条件为:argument.length >= fn.length
// 3、执行闭包的最终出口是执行fn函数
// 4、在没到出口时,调用curry 返回闭包(参数传入辅助函数调用的结果和下一闭包的出口条件) |
如果被curry的函数参数长度不固定呢,像这种 |
我想问一下这段代码,问题写在注释中了 |
定义
维基百科中对柯里化 (Currying) 的定义为:
翻译成中文:
在数学和计算机科学中,柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。
举个例子:
用途
我们会讲到如何写出这个 curry 函数,并且会将这个 curry 函数写的很强大,但是在编写之前,我们需要知道柯里化到底有什么用?
举个例子:
想想 jQuery 虽然有$.ajax 这样通用的方法,但是也有 $ .get 和 $.post 的语法糖。(当然 jQuery 底层是否是这样做的,我就没有研究了)。
curry 的这种用途可以理解为:参数复用。本质上是降低通用性,提高适用性。
可是即便如此,是不是依然感觉没什么用呢?
如果我们仅仅是把参数一个一个传进去,意义可能不大,但是如果我们是把柯里化后的函数传给其他函数比如 map 呢?
举个例子:
比如我们有这样一段数据:
如果我们要获取所有的 name 值,我们可以这样做:
不过如果我们有 curry 函数:
我们为了获取 name 属性还要再编写一个 prop 函数,是不是又麻烦了些?
但是要注意,prop 函数编写一次后,以后可以多次使用,实际上代码从原本的三行精简成了一行,而且你看代码是不是更加易懂了?
person.map(prop('name'))
就好像直白的告诉你:person 对象遍历(map)获取(prop) name 属性。是不是感觉有点意思了呢?
第一版
未来我们会接触到更多有关柯里化的应用,不过那是未来的事情了,现在我们该编写这个 curry 函数了。
一个经常会看到的 curry 函数的实现为:
我们可以这样使用:
已经有柯里化的感觉了,但是还没有达到要求,不过我们可以把这个函数用作辅助函数,帮助我们写真正的 curry 函数。
第二版
我们验证下这个函数:
效果已经达到我们的预期,然而这个 curry 函数的实现好难理解呐……
为了让大家更好的理解这个 curry 函数,我给大家写个极简版的代码:
大家先从理解这个 curry 函数开始。
当执行 fn1() 时,函数返回:
当执行 fn1()() 时,函数返回:
当执行 fn1()()() 时,函数返回:
当执行 fn1()()()() 时,因为此时 length > 2 为 false,所以执行 fn():
再回到真正的 curry 函数,我们以下面的例子为例:
当执行 fn1("a", "b") 时:
当执行 fn1("a", "b")("c") 时,函数返回:
当执行 fn1("a", "b")("c")("d") 时,此时 arguments.length < length 为 false ,执行 fn(arguments),相当于:
函数执行结束。
所以,其实整段代码又很好理解:
sub_curry 的作用就是用函数包裹原函数,然后给原函数传入之前的参数,当执行 fn0(...)(...) 的时候,执行包裹函数,返回原函数,然后再调用 sub_curry 再包裹原函数,然后将新的参数混合旧的参数再传入原函数,直到函数参数的数目达到要求为止。
如果要明白 curry 函数的运行原理,大家还是要动手写一遍,尝试着分析执行步骤。
更易懂的实现
当然了,如果你觉得还是无法理解,你可以选择下面这种实现方式,可以实现同样的效果:
或许大家觉得这种方式更好理解,又能实现一样的效果,为什么不直接就讲这种呢?
因为想给大家介绍各种实现的方法嘛,不能因为难以理解就不给大家介绍呐~
第三版
curry 函数写到这里其实已经很完善了,但是注意这个函数的传参顺序必须是从左到右,根据形参的顺序依次传入,如果我不想根据这个顺序传呢?
我们可以创建一个占位符,比如这样:
我们直接看第三版的代码:
写在最后
至此,我们已经实现了一个强大的 curry 函数,可是这个 curry 函数符合柯里化的定义吗?柯里化可是将一个多参数的函数转换成多个单参数的函数,但是现在我们不仅可以传入一个参数,还可以一次传入两个参数,甚至更多参数……这看起来更像一个柯里化 (curry) 和偏函数 (partial application) 的综合应用,可是什么又是偏函数呢?下篇文章会讲到。
专题系列
JavaScript专题系列目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript专题系列预计写二十篇左右,主要研究日常开发中一些功能点的实现,比如防抖、节流、去重、类型判断、拷贝、最值、扁平、柯里、递归、乱序、排序等,特点是研(chao)究(xi) underscore 和 jQuery 的实现方式。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: