JS|JS 5高阶函数分享
目录
- 1、前言
- 2、递归
- 3、回调函数
- 3.1匿名回调函数
- 3.2带参数的回调函数
- 3.3回调函数的优缺点
- 4、自调函数
- 5、为值的函数
- 6、闭包
1、前言
在JavaScript中,函数实际上也是一个数据,也就是说函数也可以赋值给一个变量。本篇文章就来介绍一些JavaScript中的高阶函数的用法。
2、递归
所谓的递归,就是指函数自己调用自己;用一个故事来说呢就是:从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?“从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?‘从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?……'” 。
从某种意义上说,递归近似于循环。两者都重复执行相同的代码,并且两者都需要一个终止条件,以避免无限循环或者无限递归。
递归所需要的必要条件如下:
- 子问题跟原始问题一样,且更为简单
- 必须有个出口
- 通过使用函数名实现
- 通过使用arguments.callee属性实现。
var v = 1 // 出口条件function fun() {console.log('第' + v + '次调用函数')v++if (v <= 3) {fun()}}fun()
执行结果如下
第1次调用函数
第2次调用函数
第3次调用函数
3、回调函数
然函数与任何可以被赋值给变量的数据是相同的,那么它当然可以像其他数据那样被定义、删除、拷贝,以及当成参数传递给其他函数。
当一个函数作为参数传递给另一个函数时,作为参数的函数被称之为回调函数。作为使用回调函数的函数称为目标函数(外层函数)
示例代码如下所示:
// 定义一个函数,这个函数有两个函数类型的参数,然后分别执行那两个函数,并返回它们的和。function sum(a, b) {// 目标函数return a() + b()}function one() {// 回调函数return 1}function two() {// 回调函数return 2}console.log(sum(one, two)) // 3
代码执行流程如下:
当执行
sum
函数时,传入两个实参,在sum
函数中,会将两个实参作为函数执行,并将返回值计算并返回。3.1匿名回调函数
所谓匿名回调函数,就是目标函数中的参数是没有名称的函数,将上一段代码修改为使用匿名回调函数
// 定义一个函数,这个函数有两个函数类型的参数,然后分别执行那两个函数,并返回它们的和。function sum(a, b) {// 目标函数return a() + b()}console.log(sum(function () {// 匿名回调函数return 1},function () {//匿名回调函数return 2},),) // 3
3.2带参数的回调函数
【JS|JS 5高阶函数分享】回调函数是可以增加参数的,示例代码如下:
function multiplyByTwo(list, callback) {list.forEach(function (v, i) {callback(v * 2, i)})}var list = [1, 2, 3]multiplyByTwo(list, function (v, i) {list[i] = v})console.log(list) // [ 2, 4, 6 ]
3.3回调函数的优缺点
- 匿名回调函数节省了全局命名空间
- 将私有的数据内容开放给指定位置使用
- 保证封装性——虽然可以使用私有数据,但是并不知道来源
- 有助于提升性能
4、自调函数
所谓的自调函数,就是定义后立即调用的函数,示例代码如下所示:
; (function () {console.log('自调函数')})()
这种语法看上去有点唬人,其实没有什么,我们只需将匿名函数的定义放进一对括号中,然后外面再紧跟一对括号即可。
语法结构如下图所示:
文章图片
自调函数除了以上两种方式外,还有以下几种不常用的方式,示例代码如下:
; +(function (v) {// 形参var w = 100 // 局部变量console.log('自调函数' + v)})(1) // 实参!(function (v) {var w = 100 // 局部变量console.log('自调函数' + v)})(2)~(function (v) {var w = 100 // 局部变量console.log('自调函数' + v)})(3)
使用自调匿名函数的好处是不会产生任何全局变量。
缺点在于这样的函数是无法重复执行的(除非将它放在某个循环或其他函数中)。这也使得即时函数非常适合于执行一些一次性的或初始化的任务。
5、为值的函数
将一个函数作为另一个函数的结果并返回,作为结果返回的函数称之为作为值的函数。
示例代码如下:
function outer() {var v = 100// 在函数的函数体中定义另一个函数 -> 内部(私有)函数return function () {// 使用匿名函数return v * 2}}var result = outer()console.log(result) // [Function]
这样做的好处是:
- 有助于我们确保全局名字空间的纯净性(这意味着命名冲突的机会很小)。
- 确保私有性 — 这使我们可以选择只将一些必要的函数暴露给“外部世界”,而保留属于自己的函数,使它们不为该应用程序的其他部分所用。
6、闭包
闭包是在函数中提出的概念,简单来说就是一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行。当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了。
实际上闭包可以看做一种更加广义的函数概念。因为其已经不再是传统意义上定义的函数。
闭包的条件:
- 外部函数中定义了内部函数。
- 外部函数是具有返回值,且返回值为内部函数。
- 内部函数还引用了外部函数的变量。
- 作用域没有那么直观。
- 因为变量不会被垃圾回收所以有一定的内存占用问题。
- 可以使用同级的作用域。
- 读取其他元素的内部变量。
- 延长作用域。
- 避免污染全局变量
我们可以将函数的执行分成两个阶段,即预编译阶段和执行阶段;
- 在预编译阶段,如果发现内部函数使用了外部函数的变量,它就会在内存中 创建一个闭包对象并保存相对应的值,如果已经存在闭包,则只需要增加对应属性值即可。
- 在执行完成后,函数执行上下文会被校徽,函数对闭包对象的引用也会被销毁,但其内部函数还持有该闭包的引用,所以内部函数还可以继续使用外部函数的变量
闭包的实现的demo:
// 1. 通过返回的内部函数来操作函数中的局部变量function fun () {var v = 100; // 局部变量// 通过返回一个对象的方式访问局部变量v 来完成闭包return {set: function (x) {v = x; },get: function () {return v}}}var result = fun(); result.set(200)console.log(result.get()); // 200
// 2. 定义一个局部变量,计算该函数一共调用几次var generate_count = function () {var container = 0; return function () {container++console.log(`这是第${container}次调用`); }}var result = generate_count(); result(); // 这是第1次调用result(); // 这是第2次调用result(); // 这是第3次调用
// 3.修改 Math.pow() 函数,让求一个数的平方或者立方时,不需要每次传递第二个参数/*Math.pow(4, 2) // 求4的平方Math.pow(4, 3) // 求4的立方*/// 写一个函数生成器function makePower (power) {return (number) => {return Math.pow(number, power)}}// 平方let power2 = makePower(2)// 立方let power3 = makePower(3)// 求4的平方console.log(power2(4)) // 16// 求4的立方console.log(power3(4)) // 62
总结:
本篇文章介绍了JavaScript中的5个高阶函数,分别是递归、回调函数、自调函数、作为值得函数以及闭包的使用以及实现。
到此这篇关于JS 5高阶函数的文章就介绍到这了,更多相关JS 阶函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- 第326天
- 一起来学习C语言的字符串转换函数
- C语言字符函数中的isalnum()和iscntrl()你都知道吗
- C语言浮点函数中的modf和fmod详解
- C语言中的时间函数clock()和time()你都了解吗
- 姚老师互动问答会|姚老师互动问答会 # 问题001(如何更有智慧的和身边人分享金刚智慧())
- 焦点学习田源分享第267天《来访》
- 《偶得》
- 2018.03.18
- 坚持分享第104天