ÐаÑÑиÑование â пÑодвинÑÑÐ°Ñ ÑÐµÑ Ð½Ð¸ÐºÐ° Ð´Ð»Ñ ÑабоÑÑ Ñ ÑÑнкÑиÑми. Ðна иÑполÑзÑеÑÑÑ Ð½Ðµ ÑолÑко в JavaScript, но и в дÑÑÐ³Ð¸Ñ ÑзÑÐºÐ°Ñ .
ÐаÑÑиÑование â ÑÑо ÑÑанÑÑоÑмаÑÐ¸Ñ ÑÑнкÑий Ñаким обÑазом, ÑÑÐ¾Ð±Ñ Ð¾Ð½Ð¸ пÑинимали аÑгÑменÑÑ Ð½Ðµ как f(a, b, c), а как f(a)(b)(c).
ÐаÑÑиÑование не вÑзÑÐ²Ð°ÐµÑ ÑÑнкÑиÑ. Ðно пÑоÑÑо ÑÑанÑÑоÑмиÑÑÐµÑ ÐµÑ.
ÐавайÑе ÑнаÑала поÑмоÑÑим на пÑимеÑ, ÑÑÐ¾Ð±Ñ Ð»ÑÑÑе понÑÑÑ, о ÑÑм ÑеÑÑ, а поÑом на пÑакÑиÑеÑкое пÑименение каÑÑиÑованиÑ.
Создадим вÑпомогаÑелÑнÑÑ ÑÑнкÑÐ¸Ñ curry(f), коÑоÑÐ°Ñ Ð²ÑполнÑÐµÑ ÐºÐ°ÑÑиÑование ÑÑнкÑии f Ñ Ð´Ð²ÑÐ¼Ñ Ð°ÑгÑменÑами. ÐÑÑгими Ñловами, curry(f) Ð´Ð»Ñ ÑÑнкÑии f(a, b) ÑÑанÑÑоÑмиÑÑÐµÑ ÐµÑ Ð² f(a)(b).
function curry(f) { // curry(f) вÑполнÑÐµÑ ÐºÐ°ÑÑиÑование
return function(a) {
return function(b) {
return f(a, b);
};
};
}
// иÑполÑзование
function sum(a, b) {
return a + b;
}
let curriedSum = curry(sum);
alert( curriedSum(1)(2) ); // 3
Ðак Ð²Ñ Ð²Ð¸Ð´Ð¸Ñе, ÑеализаÑÐ¸Ñ Ð´Ð¾Ð²Ð¾Ð»Ñна пÑоÑÑа: ÑÑо две обÑÑÑки.
- РезÑлÑÑаÑ
curry(func)â обÑÑÑкаfunction(a). - Ðогда она вÑзÑваеÑÑÑ ÐºÐ°Ðº
sum(1), аÑгÑÐ¼ÐµÐ½Ñ ÑÐ¾Ñ ÑанÑеÑÑÑ Ð² лекÑиÑеÑком окÑÑжении и возвÑаÑаеÑÑÑ Ð½Ð¾Ð²Ð°Ñ Ð¾Ð±ÑÑÑкаfunction(b). - Ðалее Ñже ÑÑа обÑÑÑка вÑзÑваеÑÑÑ Ñ Ð°ÑгÑменÑом
2и пеÑедаÑÑ Ð²Ñзов к оÑигиналÑной ÑÑнкÑииsum.
Ðолее пÑодвинÑÑÑе ÑеализаÑии каÑÑиÑованиÑ, как напÑÐ¸Ð¼ÐµÑ _.curry из библиоÑеки lodash, возвÑаÑаÑÑ Ð¾Ð±ÑÑÑкÑ, коÑоÑÐ°Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»ÑÐµÑ Ð·Ð°Ð¿ÑÑÑиÑÑ ÑÑнкÑÐ¸Ñ ÐºÐ°Ðº обÑÑнÑм обÑазом, Ñак и ÑаÑÑиÑно.
function sum(a, b) {
return a + b;
}
let curriedSum = _.curry(sum); // иÑполÑзÑем _.curry из lodash
alert( curriedSum(1, 2) ); // 3, можно вÑзÑваÑÑ ÐºÐ°Ðº обÑÑно
alert( curriedSum(1)(2) ); // 3, а можно ÑаÑÑиÑно
ÐаÑÑиÑование? ÐаÑем?
ЧÑÐ¾Ð±Ñ Ð¿Ð¾Ð½ÑÑÑ Ð¿Ð¾Ð»ÑÐ·Ñ Ð¾Ñ ÐºÐ°ÑÑиÑованиÑ, нам опÑеделÑнно нÑжен пÑÐ¸Ð¼ÐµÑ Ð¸Ð· ÑеалÑной жизни.
ÐапÑимеÑ, Ñ Ð½Ð°Ñ ÐµÑÑÑ ÑÑнкÑÐ¸Ñ Ð»Ð¾Ð³Ð¸ÑÐ¾Ð²Ð°Ð½Ð¸Ñ log(date, importance, message), коÑоÑÐ°Ñ ÑоÑмаÑиÑÑÐµÑ Ð¸ вÑÐ²Ð¾Ð´Ð¸Ñ Ð¸Ð½ÑоÑмаÑиÑ. Ð ÑеалÑнÑÑ
пÑоекÑаÑ
Ñ ÑакиÑ
ÑÑнкÑий еÑÑÑ Ð¼Ð½Ð¾Ð³Ð¾ полезнÑÑ
возможноÑÑей, напÑимеÑ, поÑÑлаÑÑ Ð»Ð¾Ð³Ð¸ по ÑеÑи, здеÑÑ Ð´Ð»Ñ Ð¿ÑоÑÑоÑÑ Ð¸ÑполÑзÑем alert:
function log(date, importance, message) {
alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}
Ð ÑепеÑÑ Ð´Ð°Ð²Ð°Ð¹Ñе пÑименим к ней каÑÑиÑование!
log = _.curry(log);
ÐоÑле ÑÑого log пÑÐ¾Ð´Ð¾Ð»Ð¶Ð°ÐµÑ ÑабоÑаÑÑ Ð½Ð¾ÑмалÑно:
log(new Date(), "DEBUG", "some debug"); // log(a, b, c)
â¦Ðо Ñакже ÑабоÑÐ°ÐµÑ Ð²Ð°ÑÐ¸Ð°Ð½Ñ Ñ ÐºÐ°ÑÑиÑованием:
log(new Date())("DEBUG")("some debug"); // log(a)(b)(c)
ÐавайÑе Ñделаем ÑдобнÑÑ ÑÑнкÑÐ¸Ñ Ð´Ð»Ñ Ð»Ð¾Ð³Ð¾Ð² Ñ ÑекÑÑим вÑеменем:
// logNow бÑÐ´ÐµÑ ÑаÑÑиÑнÑм пÑименением ÑÑнкÑии log Ñ ÑикÑиÑованнÑм пеÑвÑм аÑгÑменÑом
let logNow = log(new Date());
// иÑполÑзÑем еÑ
logNow("INFO", "message"); // [HH:mm] INFO message
ТепеÑÑ logNow â ÑÑо log Ñ ÑикÑиÑованнÑм пеÑвÑм аÑгÑменÑом, инаÑе говоÑÑ, «ÑаÑÑиÑно пÑименÑннаÑ» или «ÑаÑÑиÑнаÑ» ÑÑнкÑиÑ.
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ пойÑи далÑÑе и ÑделаÑÑ ÑдобнÑÑ ÑÑнкÑÐ¸Ñ Ð´Ð»Ñ Ð¸Ð¼ÐµÐ½Ð½Ð¾ оÑладоÑнÑÑ Ð»Ð¾Ð³Ð¾Ð² Ñ ÑекÑÑим вÑеменем:
let debugNow = logNow("DEBUG");
debugNow("message"); // [HH:mm] DEBUG message
ÐÑак:
- ÐÑ Ð½Ð¸Ñего не поÑеÑÑли поÑле каÑÑиÑованиÑ:
logвÑÑ Ñак же можно вÑзÑваÑÑ Ð½Ð¾ÑмалÑно. - ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ легко ÑоздаваÑÑ ÑаÑÑиÑно пÑименÑннÑе ÑÑнкÑии, как Ñделали Ð´Ð»Ñ Ð»Ð¾Ð³Ð¾Ð² Ñ ÑекÑÑим вÑеменем.
ÐÑодвинÑÑÐ°Ñ ÑеализаÑÐ¸Ñ ÐºÐ°ÑÑиÑованиÑ
Ð ÑлÑÑае, еÑли вам инÑеÑеÑÐ½Ñ Ð´ÐµÑали, Ð²Ð¾Ñ Â«Ð¿ÑодвинÑÑаÑ» ÑеализаÑÐ¸Ñ ÐºÐ°ÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð»Ñ ÑÑнкÑий Ñ Ð¼Ð½Ð¾Ð¶ÐµÑÑвом аÑгÑменÑов, коÑоÑÑÑ Ð¼Ñ Ð¼Ð¾Ð³Ð»Ð¸ Ð±Ñ Ð¸ÑполÑзоваÑÑ Ð²ÑÑе.
Ðна оÑÐµÐ½Ñ ÐºÐ¾ÑоÑкаÑ:
function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
}
}
};
}
ÐÑимеÑÑ Ð¸ÑполÑзованиÑ:
function sum(a, b, c) {
return a + b + c;
}
let curriedSum = curry(sum);
alert( curriedSum(1, 2, 3) ); // 6, вÑÑ ÐµÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ вÑзÑваÑÑ Ð½Ð¾ÑмалÑно
alert( curriedSum(1)(2,3) ); // 6, каÑÑиÑование пеÑвого аÑгÑменÑа
alert( curriedSum(1)(2)(3) ); // 6, каÑÑиÑование вÑеÑ
аÑгÑменÑов
Ðовое curry вÑглÑÐ´Ð¸Ñ ÑложноваÑо, но на Ñамом деле его легко понÑÑÑ.
РезÑлÑÑÐ°Ñ Ð²Ñзова curry(func) â ÑÑо обÑÑÑка curried, коÑоÑÐ°Ñ Ð²ÑглÑÐ´Ð¸Ñ Ñак:
// func -- ÑÑнкÑиÑ, коÑоÑÑÑ Ð¼Ñ ÑÑанÑÑоÑмиÑÑем
function curried(...args) {
if (args.length >= func.length) { // (1)
return func.apply(this, args);
} else {
return function pass(...args2) { // (2)
return curried.apply(this, args.concat(args2));
}
}
};
Ðогда Ð¼Ñ Ð·Ð°Ð¿ÑÑкаем еÑ, еÑÑÑ Ð´Ð²Ðµ веÑви вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ if:
- ÐÑзваÑÑ ÑейÑаÑ: еÑли колиÑеÑÑво пеÑеданнÑÑ
аÑгÑменÑов
argsÑÐ¾Ð²Ð¿Ð°Ð´Ð°ÐµÑ Ñ ÐºÐ¾Ð»Ð¸ÑеÑÑвом аÑгÑменÑов пÑи обÑÑвлении ÑÑнкÑии (func.length) или болÑÑе, Ñогда вÑзов пÑоÑÑо пеÑÐµÑ Ð¾Ð´Ð¸Ñ Ðº ней. - ЧаÑÑиÑное пÑименение: в пÑоÑивном ÑлÑÑае
funcне вÑзÑваеÑÑÑ ÑÑазÑ. ÐмеÑÑо ÑÑого, возвÑаÑаеÑÑÑ Ð´ÑÑÐ³Ð°Ñ Ð¾Ð±ÑÑÑкаpass, коÑоÑÐ°Ñ Ñнова пÑимениÑcurried, пеÑедав пÑедÑдÑÑие аÑгÑменÑÑ Ð²Ð¼ÐµÑÑе Ñ Ð½Ð¾Ð²Ñми. ÐаÑем пÑи новом вÑзове Ð¼Ñ Ð¾Ð¿ÑÑÑ Ð¿Ð¾Ð»ÑÑим либо новое ÑаÑÑиÑное пÑименение (еÑли аÑгÑменÑов недоÑÑаÑоÑно) либо, наконеÑ, ÑезÑлÑÑаÑ.
ÐапÑимеÑ, давайÑе поÑмоÑÑим, ÑÑо пÑоизойдÑÑ Ð² ÑлÑÑае sum(a, b, c). У Ð½ÐµÑ ÑÑи аÑгÑменÑа, Ñак ÑÑо sum.length = 3.
ÐÐ»Ñ Ð²Ñзова curried(1)(2)(3):
- ÐеÑвÑй вÑзов
curried(1)запоминаеÑ1в ÑвоÑм лекÑиÑеÑком окÑÑжении и возвÑаÑÐ°ÐµÑ Ð¾Ð±ÑÑÑкÑpass. - ÐбÑÑÑка
passвÑзÑваеÑÑÑ Ñ(2): она беÑÑÑ Ð¿ÑедÑдÑÑие аÑгÑменÑÑ (1), обÑединÑÐµÑ Ð¸Ñ Ñ Ñем, ÑÑо полÑÑила Ñама(2)и вÑзÑваеÑcurried(1, 2)Ñо вÑеми ними. Так как ÑиÑло аÑгÑменÑов вÑÑ ÐµÑÑ Ð¼ÐµÐ½ÑÑе 3-Ñ ,curryвозвÑаÑаеÑpass. - ÐбÑÑÑка
passвÑзÑваеÑÑÑ Ñнова Ñ(3). ÐÐ»Ñ ÑледÑÑÑего вÑзоваpass(3)беÑÑÑ Ð¿ÑедÑдÑÑие аÑгÑменÑÑ (1,2) и добавлÑÐµÑ Ðº ним3, Ð´ÐµÐ»Ð°Ñ Ð²Ñзовcurried(1, 2, 3)â Ð½Ð°ÐºÐ¾Ð½ÐµÑ 3 аÑгÑменÑа, и они пеÑедаÑÑÑÑ Ð¾ÑигиналÑной ÑÑнкÑии.
ÐÑли вÑÑ ÐµÑÑ Ð½Ðµ понÑÑно, пÑоÑÑо ÑаÑпиÑиÑе поÑледоваÑелÑноÑÑÑ Ð²Ñзовов на бÑмаге.
ÐÐ»Ñ ÐºÐ°ÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð° ÑÑнкÑÐ¸Ñ Ñ ÑикÑиÑованнÑм колиÑеÑÑвом аÑгÑменÑов.
ФÑнкÑиÑ, коÑоÑÐ°Ñ Ð¸ÑполÑзÑÐµÑ Ð¾ÑÑаÑоÑнÑе паÑамеÑÑÑ, Ñипа f(...args), Ñак каÑÑиÑоваÑÑ Ð½Ðµ полÑÑиÑÑÑ.
Ðо опÑеделениÑ, каÑÑиÑование должно пÑевÑаÑаÑÑ sum(a, b, c) в sum(a)(b)(c).
Ðо, как бÑло опиÑано, болÑÑинÑÑво ÑеализаÑий каÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð² JavaScript более пÑодвинÑÑÑ: они Ñакже оÑÑавлÑÑÑ Ð²Ð°ÑÐ¸Ð°Ð½Ñ Ð²Ñзова ÑÑнкÑии Ñ Ð½ÐµÑколÑкими аÑгÑменÑами.
ÐÑого
ÐаÑÑиÑование â ÑÑо ÑÑанÑÑоÑмаÑиÑ, коÑоÑÐ°Ñ Ð¿ÑевÑаÑÐ°ÐµÑ Ð²Ñзов f(a, b, c) в f(a)(b)(c). Ð JavaScript ÑеализаÑÐ¸Ñ Ð¾Ð±ÑÑно позволÑÐµÑ Ð²ÑзÑваÑÑ ÑÑнкÑÐ¸Ñ Ð¾Ð±Ð¾Ð¸Ð¼Ð¸ ваÑианÑами: либо ноÑмалÑно, либо возвÑаÑÐ°ÐµÑ ÑаÑÑиÑно пÑименÑннÑÑ ÑÑнкÑиÑ, еÑли колиÑеÑÑво аÑгÑменÑов недоÑÑаÑоÑно.
ÐаÑÑиÑование позволÑÐµÑ Ð»ÐµÐ³ÐºÐ¾ полÑÑаÑÑ ÑаÑÑиÑнÑе ÑÑнкÑии. Ðак Ð¼Ñ Ð²Ð¸Ð´ÐµÐ»Ð¸ в пÑимеÑаÑ
Ñ Ð»Ð¾Ð³Ð°Ð¼Ð¸: ÑнивеÑÑалÑÐ½Ð°Ñ ÑÑнкÑÐ¸Ñ log(date, importance, message) поÑле каÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð½Ð°Ð¼ ÑаÑÑиÑно пÑименÑннÑÑ ÑÑнкÑиÑ, когда вÑзÑваеÑÑÑ Ñ Ð¾Ð´Ð½Ð¸Ð¼ аÑгÑменÑом, как log(date) или двÑÐ¼Ñ Ð°ÑгÑменÑами, как log(date, importance).
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)