初学者指南,函数式javascript:局部套用

局部套用或局部应用是一个会让那些熟悉传统javascript代码编写方式的人听起来感到困惑的函数式技术,但是如果应用得当的话,它确实可以让你的javascript代码更具有可读性。

更强的可读性,更强的灵活性

函数式javascript代码的一个优势在于它的代码更加简短,严格,它可以用最少行数和更少重复性的代码说到点子上,当然,有时候这会牺牲可读性。而在你熟悉这种函数式编程的工作方式之前,以这种方式编写的代码会让你更难阅读、更难理解!

如果你以前遇到过局部套用这一术语,但是从来不知道这是什么意思,那么你是可以被原谅的,因为他们认为这是一些你不需要烦恼的奇怪的技术。但是局部套用实际上是一个非常简单的概念,它解决了我们在处理函数参数时的一些熟悉的问题,并且为开发者开放了一系列灵活的选项。

什么是局部套用?

简而言之,局部套用是构造函数允许你在其中局部应用函数参数的一种方式,这意味着你可以传递函数所期望的所有参数并且得到结果,或者传递这个参数的子集并且返回一个等待剩余参数的函数。真的就是这么简单。

局部套用是一种类似Haskell和Scala这样围绕函数式概念的语言元素,javascript有函数式功能,但局部套用不是默认的创建方式(至少在当前版本的语言),但是我们依旧知道了一些函数式的技巧,并且我们也可以在javascript中让局部套用为我们工作。

为了理解局部套用是如何工作的,让我们在javascript中使用熟悉的语法来创建第一个我们想要的具有局部套用功能的函数。举个例子:让我们来想象一个通过名字来问候别人的函数,我们都知道怎么创建一个简单的带有名字和问候方式的问候函数,并且在控制台中输出带有名字的问候的日志:

var greet = function(greeting,name){
    console.log(greeting+","+name);
};
greet("Hello","Heidi");        // "Hello,Heidi"

这个函数需要 name 和 greeting 作为参数传递进来,以便能正常工作,但是我们可以通过使用简单的嵌套的局部套用来重写这个函数,这样的话基础函数就只需要 greeting 一个参数,并且该函数返回另外一个带有我们想要问候的人的名字的函数。

我们的第一个局部套用

var greetCurried = function(greeting){
    return function(name){
        console.log(greeting+","+name);
    };
};

我们通过这个微小的调整所写的函数让我们创建了一个可以有任何类型的问候方式的新函数,并且将我们想要问候的人的名字传递给这个新函数:

var greetHello = greetCurried("Hello");
greetHello("Heidi");   // "Hello,Heidi"
greetHello("Eddie");   // "Hello,Eddie"

我们也可以直接调用原始的局部套用的函数,只需要在每一组单独的括号中传递参数,保证每个参数的正确性:

greetCurried("Hi there")("Howard");  // "Hi there,Howard"

为什么不在你的浏览器中试试呢?

这是javascript代码:

这是浏览器控制台中的效果:                 

局部套用所有的东西

非常酷的是,既然我们已经学会了如何使用这种方法来处理参数从而修改我们的传统函数,我们同样可以使用这种方法来处理更多我们想要的参数:

var greetDeeplyCurried = function(greeting){
    return function(separator){
        return function(emphasis){
            return function(name){
                console.log(greeting+separator+name+emphasis);
            };
        };
    };
};

我们的函数有四个参数和有两个参数具有同样的灵活性,不管嵌套有多深,我们都可以创建新的自定义的函数来尽可能多的问候那些我们挑选出来的适合我们目的的人。

var greetAwkwardly = greetDeeplyCurried("Hello")("...")("?");
greetAwkwardly("Heidi");  // "Hello...Heidi?"
greetAwkwardly("Eddie");  // "Hello...Eddie?"

更重要的是,当我们在原始的局部套用函数里创建自定义的变量的时候,我们可以传递尽可能多的参数,(通过)创建一个可以获取适当的附加参数的数量,每一个被传进来的参数都在它自己的括号(即作用范围)中:

var sayHello = greetDeeplyCurried("Hello")(", ");
sayHello(".")("Heidi");  // "Hello, Heidi."
sayHello(".")("Eddie");  // "Hello, Eddie."

并且我们可以很容易的定义从属变量:

var askHello = sayHello("?");
askHello("Heidi");  // "Hello, Heidi?"
askHello("Eddie");  // "Hello, Eddie?"

这是javascript代码:

这是浏览器中的效果:

局部套用传统函数

你可以看到这种方法是多么强大,尤其是如果你需要创建很多非常详细的自定义函数。唯一的问题是语法。当你创建了局部套用函数时,你需要让嵌套函数返回,并且通过需要多组括号的新函数来调用他们,每一个括号都包含自己独立的参数,这会让人感到混乱。

为了解决这个问题,一种方法是创建一个快速的、肮脏(肮脏主要是创建了全局变量,污染了全局环境)的可以获取到一个没有任何嵌套返回的已存在的函数名称的局部套用函数(结合下列代码说明即:创建一个全局的局部套用函数,名字为curryIt,获取uncurried作为参数,uncurried是一个已存在的函数,无任何嵌套返回)。一个局部套用函数需要取出它的参数列表,并且使用取出的参数列表来返回初始函数的一个局部套用的版本:

var curryIt = function(uncurried){
    var parameters = Array.prototype.slice.call(arguments,1);
    return function(){
        return uncurried.apply(this,parameters.concat(Array.prototype.slice.call(arguments,0)));
    };
};

使用这个,我们传递一个带有任意数量参数(正如我们预先想要的那么多的数量)的函数名字,我们得到的是一个等待剩余参数的函数:

var greeter = function(greeting, separator, emphasis, name) {
  console.log(greeting + separator + name + emphasis);
};
var greetHello = curryIt(greeter, "Hello", ", ", ".");
greetHello("Heidi"); //"Hello, Heidi."
greetHello("Eddie"); //"Hello, Eddie."

就像以前一样,当我们通过原始的局部套用函数来创建派生函数的,我们并没有限制我们想要的参数的数量:

var greetGoodbye = curryIt(greeter, "Goodbye", ", ");
greetGoodbye(".", "Joe"); //"Goodbye, Joe."

这是javascript代码:

这是浏览器中的效果:

开始认真考虑局部套用

我们所举的几个小的局部套用函数可能无法处理所用的边界情况,例如参数的丢失或者可选,但是只要我们在传递参数时保持严格的语法,那么它确实是一个合理的工作方式。

一些函数式javascript库(例如Ramda)拥有更灵活的可以不限制所需参数的局部套用函数,并且允许你单独或者整体的来传递参数,从而创建自定义的局部套用的变量(即:

var curryIt = function(uncurried){....};

)。如果你想要使用拓展局部套用,那么这可能是一种不错方式。

不管你如何选择添加局部套用到你的编程中,选择使用嵌套括号或者你更倾向包含一个更健壮的承载函数,为你的局部套用函数想出一个一致的命名规则会让你的代码更具有可读性。函数的每一个派生变量(即超出函数给出参数的个数的变量)都应该有一个清晰的名字,这个名字能说明它的行为和预期想要的参数性质。

参数顺序

一件很重要的事就是你要记住局部套用的参数的顺序,使用我们所描述的方法,你显然需要一个能逐个进行替换(即顺序替换)的参数。

事先考虑参数的顺序会让你更容易的为局部套用定计划,并且将它应用到你的工作中。并且当你在设计函数时考虑在你的顺序参数列表中哪些参数改变次数可能最少将会是一个好的习惯。

结论

局部套用在函数式javascript中是一个非常有用的技术。它允许你生成一个很小的库,轻松配置表现一致的函数,能快速使用,并且当别人阅读你的代码的时候可以理解。增加局部套用到你的编程实践中将会促使你在代码中使用部分应用功能,避免了潜在的重复性,并且可以让你在写命名和处理函数参数的时候有更好的习惯。

时间: 2024-08-05 11:16:57

初学者指南,函数式javascript:局部套用的相关文章

HTML5 & CSS3初学者指南(3) – HTML5新特性

介绍 本文介绍了 HTML5 的一些新特性.主要包含以下几个方面: Web 存储 地理位置 拖放 服务器发送事件 Web存储 HTML5 Web 存储的设计与构想是一个更好的机制来存储客户端的网络数据.它是通过一个网络浏览器作为客户端数据库实现的,它允许网页以键值对的形式来存储数据. 它具有以下特征: 每个原始网站/域最多可存储 5MB 的数据. 你可以通过属性和方法来使用 JavaScript 操作 web 存储器中的数据实现访问. 就像 cookies,你可以选择将保持数据(维持),即使你已

HTML5 & CSS3 初学者指南(4) – Canvas使用

介绍 传统的HTML主要用于文本的创建,可以通过<img>标签插入图像,动画的实现则需要第三方插件.在这方面,传统的HTML极其缺乏满足现代网页多媒体需求的能力.HTML5的到来,带来了新的成员<canvas>标签. 什么是 Canvas? HTML5 的 Canvas 元素使用 JavaScript 在网页上绘制图像. 画布是一个矩形区域,你可以控制其每一像素. canvas 拥有多种绘制路径.矩形.圆形.字符以及添加图像的方法. 创建 Canvas 元素 向 HTML5 页面添

JavaScript 权威指南(4): JavaScript 的作用域和提升

JavaScript 权威指南(4): JavaScript 的作用域和提升 原文地址:http://dyy.im/4406.html 你知道下面的 JavaScript 程序执行时会输出什么值吗? var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar(); 答案是“10”,吃惊吗?那么下面的可能会真的让你大吃一惊: var a = 1; function b() { a = 10; return;

Java 8怎么了:局部套用vs闭包

[编者按]本文作者为专注于自然语言处理多年的 Pierre-Yves Saumont,Pierre-Yves 著有30多本主讲 Java 软件开发的书籍,自2008开始供职于 Alcatel-Lucent 公司,担任软件研发工程师. 本文主要介绍了 Java 8 中的闭包与局部套用功能,由国内 ITOM 管理平台 OneAPM 编译呈现. 关于Java 8,存在着许多错误观念.譬如,认为Java 8给Java带来了闭包特性就是其中之一.这个想法是错的,因为闭包特性从Java诞生之初就已经存在了.

HTML5&CSS3初学者指南(1) – 编写第一行代码

介绍 网络时代已经到来.现在对人们来说,每天上网冲浪已经成为一种最为常见的行为. 在网页浏览器中输入一段文本地址,就像http://www.codeproject.com,等待一下,网页就加载到浏览器窗口中.一个典型的网页是由文本.图像和链接组成的.除去内容上的差异,不同网站的网页也具有不同的外观和感受,以实现在网络上建立自己的身份品牌的目的. 如果你也曾想要了解你屏幕上的这些网页是如何被创建出并以各式各样的方式渲染的,那么这里正是你可以了解到这些知识的地方.让我们一起走进在浏览器中创建了这么多

算法初学者指南

摘自网络,对于这个训练计划,我只能膜拜,~ 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码, 因为太常用,所以要练到写时不用想,10-15 分钟内打完,甚至关掉显示器都可以把程序打 出来. 1.最短路(Floyd.Dijstra,BellmanFord) 2. 最小生成树(先写个prim,kruscal要用并查集,不好写) 3.大数(高精度)加减乘除 4.二分查找. (代码可在五行以内) 5.叉乘.判线段相交.然后写个凸包. 6.BFS.DFS,同时熟练hash表(

深网与暗网初学者指南

揭秘深网和暗网:你所不知道的互联网 事物总有正反面,网络也一样,其中的深网和暗网(互联网中无法被搜索引擎抓取到的那部分网络)已经存在多年了,不过在IoE(Internet of Everything万物互联)时代,它可能会扮演更为重要的角色. 我们时常会听到有人提起一个不为人知的网络,也就是所谓的暗网. 如果不是发生了一些大事(比如最近的丝绸之路2.0事件),可能大多数人一辈子都不会听到暗网这个名词.不过现在这个情况正在慢慢改变,一旦IoE的进化得以实现,再加上各类渗透,暗网的融合趋势便不可阻挡

HTML5 & CSS3初学者指南(2) – 样式化第一个网页

介绍 我们已经使用基本的 HTML 编写了一个网页.但是,写出来的 HTML 代码的网页看起来很平淡,没有吸引力. 如何改善这种很平淡的页面呢? 让我们开始使用网页的基本样式来改善页面效果,我们将会使用到 CSS 的功能. 正式开始 CSS 是层叠样式表的缩写,它是为网页添加样式的通用语言,在所有浏览器中都支持.最新的标准是 CSS3,这与早期版本完全向后兼容.CSS3 的规范是由 W3C 开发的,目前仍处于开发阶段,其最新的版本是 CSS Snapshot 2010. 打开你的文本编辑器,键入

RMAN 初学者指南

说明转自一个大神的笔记. RMAN 初学者指南  这篇文章是去年写的了,最初发表在chinaunix.net的oracle论坛里,收录在旧版文集中,可能很多没有看到,总有人写信要,今天乘改版之际就把它单独拿出来了. RMAN(Recovery Manager)是DBA的一个重要工具,用于备份.还原和恢复oracle数据库,前一段时间有网友找我要,可惜没时间,趁这两天出差在外没什么事,就写了一下,供初学的朋友参考.本文将介绍RMAN 的基本操作,更多的信息请参考<Oracle8i Backup &am