函数与函数式编程

函数与函数式编程

 

纵观JavaScript中全部必须须要掌握的重点知识中,函数是咱们在初学的时候最容易忽视的一个知识点。在学习的过程当中,可能会有不少人、不少文章告诉你面向对象很重要,原型很重要,但是却不多有人告诉你,面向对象中全部的重点难点,几乎都与函数息息相关。css

包括我以前几篇文章介绍的执行上下文,变量对象,闭包,this等,都是围绕函数来展开。react

我知道不少人在学习中,很急切的但愿本身快一点开始学习面向对象,学习模块,学习流行框架,而后迅速成为高手。可是我能够很负责的告诉你,关于函数的这些基础东西没理解到必定程度,那么你的学习进展必定是举步维艰的。git

因此,你们必定要重视函数!github

1、函数声明、函数表达式、匿名函数与自执行函数

关于函数在实际开发中的应用,大致能够总结为函数声明、函数表达式、匿名函数、自执行函数。面试

函数声明express

咱们知道,JavaScript中,有两种声明方式,一个是使用var的变量声明,另外一个是使用function的函数声明。编程

变量对象的建立过程当中,函数声明比变量声明具备更为优先的执行顺序,即咱们经常提到的函数声明提早。所以咱们在执行上下文中,不管在什么位置声明了函数,咱们均可以在同一个执行上下文中直接使用该函数。redux

函数表达式小程序

与函数声明不一样,函数表达式使用了var进行声明,那么咱们在确认他是否能够正确使用的时候就必须依照var的规则进行判断,即变量声明。咱们知道使用var进行变量声明,实际上是进行了两步操做。数组

一样的道理,当咱们使用变量声明的方式来声明函数时,就是咱们经常说的函数表达式。函数表达的提高方式与变量声明一致。

上例子的执行顺序为:

 

所以,因为声明方式的不一样,致使了函数声明与函数表达式在使用上的一些差别须要咱们注意,除此以外,这两种形式的函数在使用上并没有不一样。

关于上面例子中,函数表达式中的赋值操做,在其余一些地方也会被常用,咱们清楚其中的关系便可。

匿名函数

在上面咱们大概讲述了函数表达式中的赋值操做。而匿名函数,顾名思义,就是指的没有被显示进行赋值操做的函数。它的使用场景,多做为一个参数传入另外一个函数中。

在上面的例子中,fn的第一个参数传入了一个匿名函数。虽然该匿名函数没有显示的进行赋值操做,咱们没有办法在外部执行上下文中引用到它,可是在fn函数内部,咱们将该匿名函数赋值给了变量bar,保存在了fn变量对象的arguments对象中。

因为匿名函数传入另外一个函数以后,最终会在另外一个函数中执行,所以咱们也经常称这个匿名函数为回调函数。关于匿名函数更多的内容,我会在下一篇深刻探讨柯里化的文章中进行更加详细讲解。

匿名函数的这个应用场景几乎承担了函数的全部难以理解的知识点,所以咱们必定要对它的这些细节了解的足够清楚。

 

函数自执行与块级做用域

在ES5中,没有块级做用域,所以咱们经常使用函数自执行的方式来模仿块级做用域,这样就提供了一个独立的执行上下文,结合闭包,就为模块化提供了基础。

一个模块每每能够包括:私有变量、私有方法、公有变量、公有方法。

根据做用域链的单向访问,外面可能很容易知道在这个独立的模块中,外部执行环境是没法访问内部的任何变量与方法的,所以咱们能够很容易的建立属于这个模块的私有变量与私有方法。

可是共有方法和变量应该怎么办?你们还记得咱们前面讲到过的闭包的特性吗?没错,利用闭包,咱们能够访问到执行上下文内部的变量和方法,所以,咱们只须要根据闭包的定义,建立一个闭包,将你认为须要公开的变量和方法开放出来便可。

 

固然,闭包在模块中的重要做用,咱们也在讲解闭包的时候已经强调过,可是这个知识点真的过重要,须要咱们反复理解而且完全掌握,所以为了帮助你们进一步理解闭包,咱们来看看jQuery中,是如何利用咱们模块与闭包的。

在这里,咱们只须要看懂闭包与模块的部分就好了,至于内部的原型链是如何绕的,为何会这样写,我在讲面向对象的时候会为你们慢慢分析。举这个例子的目的所在,就是但愿你们可以重视函数,由于在实际开发中,它无处不在。

接下来我要分享一个高级的,很是有用的模块的应用。当咱们的项目愈来愈大,那么须要保存的数据与状态就愈来愈多,所以,咱们须要一个专门的模块来维护这些数据,这个时候,有一个叫作状态管理器的东西就应运而生。对于状态管理器,最出名的,我想非redux莫属了。虽然对于还在学习中的你们来讲,redux是一个有点高深莫测的东西,可是在咱们学习以前,能够先经过简单的方式,让你们大体了解状态管理器的实现原理,为咱们将来的学习奠基坚实的基础。

先来直接看代码。

我之因此说这是一个高级应用,是由于在单页应用中,咱们极可能会用到这样的思路。根据咱们提到过的知识,理解这个例子其实很简单,其中的难点估计就在于set方法的处理上,由于为了具备更多的适用性,所以作了不少适配,用到了递归等知识。若是你暂时看不懂,没有关系,知道如何使用就好了,上面的代码能够直接运用于实际开发。记住,当你须要保存的状态太多的时候,你就想到这一段代码就好了。

函数自执行的方式另外还有其余几种写法,诸如!function(){}()+function(){}()

2、函数参数传递方式:按值传递

还记得基本数据类型与引用数据类型在复制上的差别吗?基本数据类型复制,是直接值发生了复制,所以改变后,各自相互不影响。可是引用数据类型的复制,是保存在变量对象中的引用发生了复制,所以复制以后的这两个引用实际访问的实际是同一个堆内存中的值。当改变其中一个时,另一个天然也被改变。以下例。

当值做为函数的参数传递进入函数内部时,也有一样的差别。咱们知道,函数的参数在进入函数后,实际是被保存在了函数的变量对象中,所以,这个时候至关于发生了一次复制。以下例。

 

正是因为这样的不一样,致使了许多人在理解函数参数的传递方式时,就有许多困惑。究竟是按值传递仍是按引用传递?实际上结论仍然是按值传递,只不过当咱们指望传递一个引用类型时,真正传递的,只是这个引用类型保存在变量对象中的引用而已。为了说明这个问题,咱们看看下面这个例子。

在上面的例子中,若是person是按引用传递,那么person就会自动被修改成指向其name属性值为Gerg的新对象。可是咱们从结果中看到,person对象并未发生任何改变,所以只是在函数内部引用被修改而已。

4、函数式编程

虽然JavaScript并非一门纯函数式编程的语言,可是它使用了许多函数式编程的特性。所以了解这些特性可让咱们更加了解本身写的代码。

函数是第一等公民

所谓”第一等公民”(first class),指的是函数与其余数据类型同样,处于平等地位,能够赋值给其余变量,也能够做为参数,传入另外一个函数,或者做为别的函数的返回值。这些场景,咱们应该见过不少。

只用”表达式”,不用”语句”

“表达式”(expression)是一个单纯的运算过程,老是有返回值;”语句”(statement)是执行某种操做,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,并且都有返回值。

了解这一点,可让咱们本身在封装函数的时候养成良好的习惯。借助这个特性,咱们在学习其余API的时候,了解函数的返回值也是一个十分重要的习惯。

没有”反作用”

所谓”反作用”(side effect),指的是函数内部与外部互动(最典型的状况,就是修改全局变量的值),产生运算之外的其余结果。

函数式编程强调没有”反作用”,意味着函数要保持独立,全部功能就是返回一个新的值,没有其余行为,尤为是不得修改外部变量的值。

即所谓的只要是一样的参数传入,返回的结果必定是相等的。

闭包

闭包是函数式编程语言的重要特性,我也在前面几篇文章中说了不少关于闭包的内容。这里再也不赘述。

柯里化

理解柯里化稍微有点难,我在下一篇文章里专门单独来深刻分析。

5、函数封装

在咱们本身封装函数时,最好尽可能根据函数式编程的特色来编写。固然在许多状况下并不能彻底作到,好比函数中咱们经常会利用模块中的私有变量等。

普通封装

挂载在对象上

修改数组对象的例子,常在面试中被问到相似的,可是并不建议在实际开发中扩展原生对象。与普通封装不同的是,由于挂载在对象的原型上咱们能够经过this来访问对象的属性和方法,因此这种封装在实际使用时会有许多的难点,所以咱们必定要掌握好this。

相关文章
相关标签/搜索