JavaScript咖喱:实际应用有哪些?
我不认为我还喜欢咖喱。 我明白它做了什么,以及如何去做。 我无法想象我会使用它的情况。
你在哪里使用JavaScript的currying(或哪里是使用它的主要库)? DOM操作或一般应用程序开发示例欢迎。
其中一个答案提到animation。 像slideUp
, fadeIn
这样的函数将一个元素作为参数,通常是一个curry函数,返回高阶函数的默认“animation函数”内置。 为什么比仅仅应用具有一些默认值的高级函数更好?
使用它有什么缺点吗?
正如这里所要求的,在JavaScript currying上有一些很好的资源:
- http://www.dustindiaz.com/javascript-curry/
- Crockford,Douglas(2008) JavaScript:The Good Parts
- http://www.svendtofte.com/code/curried_javascript/ (绕过ML,跳过“ML中的速成课程”中的整个部分,然后从“如何编写curried JavaScript”开始)
- http://blog.morrisjohns.com/javascript_closures_for_dummies
- JavaScriptclosures如何工作?
- http://ejohn.org/blog/partial-functions-in-javascript(Resig先生关于平时的钱)
- http://benalman.com/news/2010/09/partial-application-in-javascript/
我会在评论中增加更多。
所以,根据这个答案,一般的咖啡和部分应用都是便利的技术。
如果通过调用相同的configuration来频繁“提炼”高级函数,则可以使用高级函数来创build简单,简洁的辅助方法(或使用Resig的部分)。
@Hank Gay
为了回应EmbiggensTheMind的评论:
我无法想象一个在JavaScript中使用自身的实例, 它是一种将具有多个参数的函数调用转换为函数调用链的技术,每个调用都有一个参数,但JavaScript在单个函数调用中支持多个参数。
在JavaScript中,我假定大多数其他的实际语言(不是lambda微积分),但是它通常与部分应用程序相关联。 约翰·雷西格(John Resig) 更好地解释了这一点 ,但其要点是要有一些适用于两个或更多参数的逻辑,而你只知道其中一些参数的值。
您可以使用部分应用程序/ currying来修复这些已知值,并返回一个只接受未知数的函数,稍后在实际拥有想要传递的值时调用它。 这提供了一个很好的方法来避免重复自己,当你一直在调用相同的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" );
下面是使用闭包的JavaScript中的一个有趣而实用的方法 :
function converter(toUnit, factor, offset, input) { offset = offset || 0; return [((offset + input) * factor).toFixed(2), toUnit].join(" "); } var milesToKm = converter.curry('km', 1.60936, undefined); var poundsToKg = converter.curry('kg', 0.45460, undefined); var farenheitToCelsius = converter.curry('degrees C', 0.5556, -32); milesToKm(10); // returns "16.09 km" poundsToKg(2.5); // returns "1.14 kg" farenheitToCelsius(98); // returns "36.67 degrees C"
这依赖于Function
一个curry
扩展,尽pipe你可以看到它只使用apply
(没有太花哨):
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))); } }
我发现类似于python的functools.partial
函数在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)); }; }
你为什么要使用它? 你想使用这个的一个常见的情况是,当你想在一个函数中绑定一个值:
var callback = partialWithScope(Object.function, obj);
现在当调用callback时, this
指向obj
。 这在事件情况下是有用的,或者节省一些空间,因为它通常缩短代码。
Currying类似于部分,不同之处在于currying返回的函数只接受一个参数(据我所知)。
这不是什么魔术或什么……只是一个匿名函数的快速简写。
部分(alert,“FOO!”)相当于function(){alert(“FOO!”);}
部分(Math.max,0)对应于函数(x){return Math.max(0,x);}
对部分( MochiKit术语,我认为其他一些库函数提供了一个.curry方法,它可以做同样的事情)的调用看起来比匿名函数略好一点,也比较less噪声。
这是一个例子。
我正在使用JQuery来处理一堆字段,以便我可以看到用户正在做什么。 代码如下所示:
$('#foo').focus(trackActivity); $('#foo').blur(trackActivity); $('#bar').focus(trackActivity); $('#bar').blur(trackActivity);
(对于非JQuery用户,我说任何时候有几个字段失去焦点,我想调用trackActivity()函数,我也可以使用匿名函数,但是我必须复制它4次,所以我把它拿出来命名。)
现在事实certificate,这些领域之一需要不同的处理。 我希望能够将这些调用中的某个parameter passing给我们的跟踪基础结构。 用咖喱,我可以。
同意Hank Gay – 这在某些真正的函数式编程语言中是非常有用的 – 因为这是必要的部分。 例如,在Haskell中,你不能将多个parameter passing给一个函数 – 你不能在纯函数式编程中做到这一点。 你一次拿一个参数,build立你的function。 在JavaScript中,这是不必要的,尽pipe人为的例子,如“转换器”。 这是相同的转换器代码,不需要currying:
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
我非常希望道格拉斯·克罗克福德(Douglas Crockford)在“JavaScript:好的部分”中提到了柯里的历史和实际使用,而不是他的贬低言论。 在阅读之后的最长时间里,我很惊讶,直到我学习函数式编程,并意识到它是从哪里来的。
经过一番思考之后,我假设有一个有效的JavaScript用例:如果你正在尝试使用JavaScript编写纯函数式编程技术。 看起来像一个罕见的用例,但。
至于使用它的图书馆,总是有function的 。
什么时候在JS中有用? 可能同时它在其他现代语言中是有用的,但是我唯一能看到我自己使用它的是与部分应用相结合的。
我会说,最有可能的是,JS中的所有animation库都使用了currying。 而不是每次调用都要传递一组受影响的元素和一个函数,描述元素应该如何行为,更高级的函数可以确保所有的时序性,所以客户通常更容易发布,像“slideUp”,“fadeIn”这样的函数,它只接受元素作为参数,只是一些curry函数返回高阶函数,内置默认的“animation函数”。
JavaScript函数在其他function语言中被称为lamda。 它可以用来编写一个新的api(更强大的function或者完整的function)来基于另一个开发者的简单input。 咖喱只是其中的一种技巧。 你可以使用它来创build一个简化的api来调用一个复杂的api。 如果你是使用简化api的开发者(例如你使用jQuery来做简单的操作),你不需要使用curry。 但如果你想创build简化的API,咖喱是你的朋友。 你必须编写一个JavaScript框架(如jQuery,mootools)或库,那么你可以欣赏它的力量。 我在http://blog.semanticsworks.com/2011/03/enhanced-curry-method.html上写了一个增强的咖喱function。; 你不需要咖喱方法来做咖喱,它只是帮助做咖喱,但你可以通过写一个函数A(){}返回另一个函数B(){}来手动执行。 为了使它更有趣,使用函数B()返回另一个函数C()。
我知道它的旧线程,但我将不得不显示如何在JavaScript库中使用它:
我将使用lodash.js库来具体描述这些概念。
例:
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!
区别:
在currying之后,我们得到一个没有参数预定义的新函数。
在部分应用之后,我们得到一个与一些参数绑定的函数。
在绑定中,我们可以绑定一个将被用来replace“this”的上下文,如果没有绑定,那么默认的任何函数都将是window作用域。
build议:没有必要重新发明轮子。 部分应用/绑定/咖喱是非常相关的。 你可以看到上面的区别。 在任何地方使用这个含义,人们会认识到你在做什么,而不会理解问题,而且你将不得不使用更less的代码。
我同意有时候希望通过创build一个伪函数来实现滚动,这个伪函数总是会填充第一个参数的值。幸运的是,我遇到了一个全新的JavaScript库jPaq(h ttp :// jpaq.org/ )提供了这个function。 关于这个库最好的事情是,你可以下载你自己的版本,只包含你将需要的代码。
我刚刚写了一个jPaq示例,其中显示了咖喱function的一些很酷的应用程序。 看看这里: Currying的string函数
只是想为Functional.js添加一些资源:
讲座/会议解释一些应用程序http://www.youtube.com/watch?v=HAcN3JyQoyY
更新了Functional.js库: https : //github.com/loop-recur/FunctionalJS一些好帮手(对不起,这里没有声望:p):/ loop-recur / PreludeJS
最近我一直在使用这个库来减lessjs IRC客户端帮助库中的重复。 这是很好的东西 – 真的有助于清理和简化代码。
另外,如果性能成为一个问题(但是这个库很轻),使用本地函数重写就很容易。
您可以使用本地绑定快速,单行解决scheme
function clampAngle(min, max, angle) { var result, delta; delta = max - min; result = (angle - min) % delta; if (result < 0) { result += delta; } return min + result; }; var clamp0To360 = clampAngle.bind(null, 0, 360); console.log(clamp0To360(405)) // 45
另一个刺伤,从诺言工作。
(免责声明:来自Python世界的JS noob,即使在那里, currying也不是那么用的,但它可以派上用场,所以我把咖喱函数分解了 – 请参阅链接)
首先,我从一个Ajax电话开始。 我有一些成功的具体处理,但在失败,我只是想给用户的反馈,调用的东西导致了一些错误 。 在我的实际代码中,我在引导面板中显示错误反馈,但是在这里只使用日志logging。
我修改了我的实时url,使其失败。
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); }
现在,在这里为了告诉用户一个批处理失败了,我需要在error handling程序中写入这个信息,因为它所得到的只是服务器的响应。
我仍然只有编码时间的信息可用 – 在我的情况下,我有一些可能的批次,但我不知道哪一个失败wo分析服务器响应失败的url。
function fail_status_specific_to_batch(d){ console.log("bad batch run, dude"); console.log("response.status:" + d.status); }
我们开始做吧。 控制台输出是:
安慰:
bad batch run, dude utility.js (line 109) response.status:404
现在,让我们稍微改变一下,使用一个可重用的通用失败处理程序,但是也可以在运行时使用已知的代码时调用上下文和事件提供的运行时信息。
... 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); }; }
安慰:
Object { user_msg="bad batch run, dude. you were calling :Run ACL now"} utility.js (line 117) response.status:404 utility.js (line 118)
更一般地说,考虑到JS中广泛的callback用法,currying似乎是一个非常有用的工具。
https://javascriptweblog.wordpress.com/2010/04/05/curry-cooking-up-tastier-functions/ http://www.drdobbs.com/open-source/currying-and-partial-functions-in- javasc / 231001821?PGNO = 2