函数与函数式编程
Posted 灿烂头
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了函数与函数式编程相关的知识,希望对你有一定的参考价值。
一、函数声明、函数表达式、匿名函数、自执行函数
函数声明
在javascript中,有两种声明方式:一个是使用var的变量声明,另一个是使用function的函数声明。
在变量对象的创建过程中,函数声明比变量声明具有更为优先的执行顺序。因此在一个执行上下文中,无论在什么位置声明了函数,都可以在这个执行上下文中直接使用该函数。
函数表达式
与函数声明不同,函数表达式是使用var进行声明。我们知道使用var进行变量声明,其实是进行了两步操作。如图所示:
同样的道理,当使用变量声明的方式来声明函数时(即函数表达式),函数表达式的提升方式与变量声明的一样。
如图所示:
因此,由于声明方式的不同,导致了函数声明与函数表达式在使用上有一些差异。除此之外,这两种形式的函数在使用上并无不同。
函数表达式中的赋值操作,在其他一些地方也会经常使用。如:
匿名函数
在函数表达式中有一个赋值的操作,匿名函数就是指没有显示进行赋值操作的函数。匿名函数多作为一个参数传入另一个函数中。如图:
在上面的例子中,fn的第一个参数传入了一个匿名函数。虽然该匿名函数没有显示进行赋值的操作,并且在外部执行上下文中无法引用到它,但是在fn函数内部,该匿名函数赋值给了变量bar,保存在了fn变量对象的arguments对象中。
由于匿名函数作为参数传入另一个函数后,最终会在另一个函数中执行,因此也常常称这个匿名函数为回调函数。
函数自执行与块级作用域
在ES5中,没有块级作用域,因此常常通过使用函数自执行的方式来模仿块级作用域。这样就提供了一个独立的执行上下文,结合闭包,就为模块化提供了基础。函数自执行其实是匿名函数的一种应用。
一个模块往往可以包括:私有变量、私有方法、公有变量、公有方法。
私有变量/方法:
根据作用域链的单向访问,外部执行环境是无法访问内部的变量与方法的。因此可以很容易的创建属于这个模块的私有变量与私有方法。
公有变量/方法:
利用闭包可以访问到执行上下文内部的变量和方法。因此,只需要创建一个闭包,将需要公开的变量和方法抛出来即可。
看看jQuery中是如何利用模块和闭包的。
在使用时,直接执行了构造函数,因为在jQuery的构造函数中通过一些手段,返回的是jQuery的实例,所以就不用每次用的时候自己new了。
二、函数参数传递方式:按值传递
当值作为函数的参数传递进入函数内部后,实际上是保存在了函数的变量对象中,这个时候相当于发生了一次复制。如下图所示:
再看一个例子:
三、函数式编程
当使用一个函数时,通常情况下就是将一些功能、逻辑等封装起来。例如想要计算一个数组中所有子项目的和。
如果不通过函数封装的方式,那么每次想要实现这个功能时,就不得不重新写一次类似的代码。这就导致会有越来越多的重复代码。
函数式编程有助于我们更好的去封装一个函数。
再看一个例子:
使用命令式编程思维的问题在于,当想要找出另外一个数组中符合某个要求的所有子项时,不得不把同样的逻辑再写一次。这样做不利于后期的维护。
而使用函数式思维编程将功能封装之后,实现同样的功能,只要写一行代码即可。如果在未来需要变动或者修改,只需要对封装的方法进行调整就可以了。有利于后期的维护。
函数式编程的几个特征:
①函数是第一等公民
函数可以赋值给其它变量,也可以作为参数传入另一个函数,也可以作为别的函数的返回值。
可以用一个简单的例子来验证一下:
②只用“表达式”,不用“语句”
“表达式”是一个单纯的运算过程,总是有返回值;“语句”是执行某种操作,没有返回值。函数式编程的要求是只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。
举个例子来了解一下:
③纯函数
纯函数:相同的输入总会得到相同的输出,并且不会产生副作用的函数。
所谓的“副作用”,指的是函数内部与外部互动(最典型的就是修改全局变量的值),产生运算以外的其它结果。
函数式编程强调没有“副作用”,意味着函数要保持独立,所有的功能就是返回一个新值,没有其它行为,尤其是不能修改外部变量的值。
举个例子来了解:
getLast1和getLast2虽然都能够获得数组的最后一项,但是getLast2改变了原数组。getLast2的封装是非常糟糕的。
④闭包
⑤柯里化
以上是关于函数与函数式编程的主要内容,如果未能解决你的问题,请参考以下文章