JavaScript咖喱:实际应用是什么?
我想我还没有学过咖喱。我了解它的作用,以及如何做。我只是想不出我会用它的情况 您在哪里使用JavaScript中的咖喱(或者使用它的主要库在哪里)?欢迎使用DOM操作或一般应用程序开发示例 提到动画。类似于JavaScript咖喱:实际应用是什么?,javascript,function,currying,partial-application,Javascript,Function,Currying,Partial Application,我想我还没有学过咖喱。我了解它的作用,以及如何做。我只是想不出我会用它的情况 您在哪里使用JavaScript中的咖喱(或者使用它的主要库在哪里)?欢迎使用DOM操作或一般应用程序开发示例 提到动画。类似于slideUp,fadeIn的函数将元素作为参数,通常是一个返回高阶函数的通用函数,内置默认的“动画函数”。为什么这比只应用带有一些默认值的高位函数要好 使用它有什么缺点吗 根据要求,这里有一些关于JavaScript咖喱的好资源: var converter = function(ratio
slideUp
,fadeIn
的函数将元素作为参数,通常是一个返回高阶函数的通用函数,内置默认的“动画函数”。为什么这比只应用带有一些默认值的高位函数要好
使用它有什么缺点吗
根据要求,这里有一些关于JavaScript咖喱的好资源:
var converter = function(ratio, symbol, input) {
return (input*ratio).toFixed(2) + " " + symbol;
}
var kilosToPoundsRatio = 2.2;
var litersToUKPintsRatio = 1.75;
var litersToUSPintsRatio = 1.98;
var milesToKilometersRatio = 1.62;
converter(kilosToPoundsRatio, "lbs", 4); //8.80 lbs
converter(litersToUKPintsRatio, "imperial pints", 2.4); //4.20 imperial pints
converter(litersToUSPintsRatio, "US pints", 2.4); //4.75 US pints
converter(milesToKilometersRatio, "km", 34); //55.08 km
- Crockford,Douglas(2008)JavaScript:好的部分
- (绕道进入ML,跳过“ML速成课程”的整个部分,从“如何编写咖喱JavaScript”开始)
- (雷西格先生照常拿钱)
因此,根据答案,咖喱和部分应用通常是方便的技巧
如果您经常通过使用相同的配置调用高级函数来“细化”高级函数,那么您可以使用(或使用Resig的partial)高级函数来创建简单、简洁的帮助器方法。对于使用它的库,始终存在一些问题
它在JS中什么时候有用?也许它在其他现代语言中同样有用,但我唯一能看到自己使用它的时候是与部分应用程序结合使用。我想说的是,JS中的所有动画库很可能都在使用Curry。不必为每次调用传递一组受影响的元素和一个函数(描述元素的行为方式)到一个更高阶的函数,该函数将确保所有计时功能,客户通常更容易发布,因为有些函数(如“slideUp”、“fadeIn”)只将元素作为参数,这只是一些返回高阶函数的curry函数,内置了默认的“animation function”。这不是什么神奇的东西。。。这只是匿名函数的一个令人愉快的简写
partial(alert,“FOO!”)
相当于function(){alert(“FOO!”);}
partial(Math.max,0)
对应于函数(x){return Math.max(0,x);}
对分部函数的调用(术语。我认为其他一些库为函数提供了一个.curry方法,该方法可以做同样的事情)看起来比匿名函数稍微好一些,噪音也更小。我发现函数类似于python的
functools。分部函数在JavaScript中更有用:
function partial(fn) {
return partialWithScope.apply(this,
Array.prototype.concat.apply([fn, this],
Array.prototype.slice.call(arguments, 1)));
}
function partialWithScope(fn, scope) {
var args = Array.prototype.slice.call(arguments, 2);
return function() {
return fn.apply(scope, Array.prototype.concat.apply(args, arguments));
};
}
你为什么要用它?当您想将函数中的this
绑定到一个值时,通常需要使用此选项:
var callback = partialWithScope(Object.function, obj);
现在,当调用callback时,这个
指向obj
。这在事件情况下很有用,或者可以节省一些空间,因为它通常会缩短代码
curry与partial类似,不同之处在于curry返回的函数只接受一个参数(据我所知)。@Hank Gay
针对EmbiggensTheMind的评论:
我想不出一个实例,它本身在JavaScript中是有用的;它是一种将具有多个参数的函数调用转换为具有单个参数的函数调用链的技术,但JavaScript支持单个函数调用中的多个参数
在JavaScript中,我假设大多数其他实际语言(不是lambda演算)都与部分应用程序相关。John Resig,但要点是,我们有一些逻辑将应用于两个或多个参数,并且您只知道其中一些参数的值
您可以使用部分应用程序/curry来修复这些已知值,并返回一个只接受未知值的函数,当您实际拥有希望传递的值时将调用该函数。这提供了一种巧妙的方法,可以避免在反复调用相同的JavaScript内置代码时重复自己的操作,而这些JavaScript内置代码的值都相同,只有一个。以约翰为例:
String.prototype.csv = String.prototype.split.partial(/,\s*/);
var results = "John, Resig, Boston".csv();
alert( (results[1] == "Resig") + " The text values were split properly" );
这里有一个例子
我正在使用JQuery检测一系列字段,以便查看用户在做什么。代码如下所示:
$('#foo').focus(trackActivity);
$('#foo').blur(trackActivity);
$('#bar').focus(trackActivity);
$('#bar').blur(trackActivity);
(对于非JQuery用户,我的意思是,每当两个字段获得或失去焦点时,我都希望调用trackActivity()函数。我也可以使用匿名函数,但我必须将其复制4次,因此我将其取出并命名。)
现在发现其中一个字段需要进行不同的处理。我希望能够将其中一个调用的参数传递给我们的跟踪基础设施。有了currying,我可以。我同意,有时您希望通过创建一个始终填充第一个参数的值的伪函数来启动程序。幸运的是,我遇到了一个名为jPaq(h)的全新JavaScript库,它提供了此功能。该库最好的一点是,您可以下载自己的版本,其中只包含您需要的代码。JavaScript函数在其他函数式语言中称为lamda。它可以用于根据其他开发人员的简单输入编写新的api(更强大或更复杂的函数)。咖喱只是其中一种技巧。您可以使用它创建一个简化的api来调用复杂的api。如果您是使用简化api的开发人员(例如,您使用jQuery进行简单操作),则不需要使用curry。但是如果你想创建简化的api,curry是你的朋友。您必须编写一个javascript框架(比如jQuery,
Function.prototype.curry = function() {
if (arguments.length < 1) {
return this; //nothing to curry with - return function
}
var __method = this;
var args = toArray(arguments);
return function() {
return __method.apply(this, args.concat([].slice.apply(null, arguments)));
}
}
var fn = function(a,b,c){
return a+b+c+(this.greet || ‘');
}
var partialFnA = _.partial(fn, 1,3);
var curriedFn = _.curry(fn);
var boundFn = _.bind(fn,object,1,3 );//object= {greet: ’!'}
curriedFn(1)(3)(5); // gives 9
or
curriedFn(1,3)(5); // gives 9
or
curriedFn(1)(_,3)(2); //gives 9
partialFnA(5); //gives 9
boundFn(5); //gives 9!
var converter = function(ratio, symbol, input) {
return (input*ratio).toFixed(2) + " " + symbol;
}
var kilosToPoundsRatio = 2.2;
var litersToUKPintsRatio = 1.75;
var litersToUSPintsRatio = 1.98;
var milesToKilometersRatio = 1.62;
converter(kilosToPoundsRatio, "lbs", 4); //8.80 lbs
converter(litersToUKPintsRatio, "imperial pints", 2.4); //4.20 imperial pints
converter(litersToUSPintsRatio, "US pints", 2.4); //4.75 US pints
converter(milesToKilometersRatio, "km", 34); //55.08 km
function ajax_batch(e){
var url = $(e.target).data("url");
//induce error
url = "x" + url;
var promise_details = $.ajax(
url,
{
headers: { Accept : "application/json" },
// accepts : "application/json",
beforeSend: function (request) {
if (!this.crossDomain) {
request.setRequestHeader("X-CSRFToken", csrf_token);
}
},
dataType : "json",
type : "POST"}
);
promise_details.then(notify_batch_success, fail_status_specific_to_batch);
}
function fail_status_specific_to_batch(d){
console.log("bad batch run, dude");
console.log("response.status:" + d.status);
}
... rest is as before...
var target = $(e.target).text();
var context = {"user_msg": "bad batch run, dude. you were calling :" + target};
var contexted_fail_notification = curry(generic_fail, context);
promise_details.then(notify_batch_success, contexted_fail_notification);
}
function generic_fail(context, d){
console.log(context);
console.log("response.status:" + d.status);
}
function curry(fn) {
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function () {
var new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
};
}