前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript进阶之路系列(一): 高阶函数

JavaScript进阶之路系列(一): 高阶函数

作者头像
刘亦枫
发布2020-04-09 10:16:20
8130
发布2020-04-09 10:16:20
举报

看了这篇文章,你就会高阶函数了,是不是听起来很牛?高阶函数,听起来很高级,其实是很接地气,大家经常会用到的东西,比如filter,map,回调函数。

高阶函数是对其他函数进行操作的函数,可以将它们作为参数或通过返回它们。简单来说,高阶函数是一个函数,它接收函数作为参数或将函数作为输出返回。

在《javascript设计模式和开发实践》中是这样定义的: 1.函数可以作为参数被传递; 2.函数可以作为返回值输出。

举个例子:

代码语言:javascript
复制
function foo(f){
        if(f instanceof Function){
            f();
        }
    }
    foo(function(){
        alert("asdf");
    })

定义了一个foo函数,foo函数传入了一个函数作为参数,foo函数里面添加判断,参数如果是函数就执行该参数。这就是一个简单的高阶函数。

回调函数(callback)

这个基本上是我们非常常用的高阶函数了,我们可以来看一下回调函数的代码:

代码语言:javascript
复制
function greeting(name) {
  alert('Hello ' + name);
}

function processUserInput(callback) {
  var name = prompt('请输入你的名字。');
  callback(name);
}

processUserInput(greeting);

定义了一个greeting函数,又定义了一个processUserInput函数,之后我们又把greeting函数作为参数传到了processUserInput中,这个就符合了高阶函数中的第一个定义,作为参数被传递。

回调函数作为高阶函数中的一种,它是干什么的呢?

回调函数是指 使用者自己定义一个函数,实现这个函数的程序内容,然后把这个函数(入口地址)作为参数传入别人(或系统)的函数中,由别人(或系统)的函数在运行时来调用的函数。

这么说,可能听不明白。

callback 一词本来用于打电话。你可以打电话(call)给别人,也可以留下电话号码,让别人回电话(callback)。回调函数的意思就是,你写了一个函数,让别人来调用,就是回调函数。

在这里插入图片描述
在这里插入图片描述

来看一看异步的回调函数:

代码语言:javascript
复制
function ff(a, b, cbk) {
    setTimeout(() => {
        cbk(a + b);
    }, 3000);
}
function f(callback) {
    var x = 3, y = 4;
    var z = 0;
    callback(x, y, function (re) {
        z = re;
        console.log(z)
    });
    console.log("主函数")
    return z;
}
f(ff);

对比来看,回调与同步、异步并没有直接的联系,回调只是一种实现方式,既可以有同步回调,也可以有异步回调,还可以有事件处理回调和延迟函数回调,这些在我们工作中有很多的使用场景。

我们可以像使用变量一样使用函数,作为另一个函数的参数,在另一个函数中作为返回结果,在另一个函数中调用它。当我们作为参数传递一个回调函数给另一个函数时,我们只传递了这个函数的定义,并没有在参数中执行它。

当包含(调用)函数拥有了在参数中定义的回调函数后,它可以在任何时候调用(也就是回调)它。

这说明回调函数并不是立即执行,而是在包含函数的函数体内指定的位置“回调”它(形如其名)。

回调函数是闭包的。

当作为参数传递一个回调函数给另一个函数时,回调函数将在包含函数函数体内的某个位置被执行,就像回调函数在包含函数的函数体内定义一样。闭包函数可以访问包含函数的作用域,所以,回调函数可以访问包含函数的变量,甚至是全局变量。

什么时候用回调函数?

我一般和别人合作项目的时候,想让人感觉我的代码写的很厉害,有时候会故意写两个回调,但是这种行为不可取的,减少代码冗余,无用的代码只会造成维护上的困难。

假如,你点击了一个按钮,你想让它执行连个函数,先执行函数A,再执行函数B,这时候就可以用回调函数了。

代码语言:javascript
复制
//定义主函数,回调函数作为参数
function A(callback) {
  callback();
  console.log('我是主函数');
}
//定义回调函数
function B(){
  setTimeout("console.log('我是回调函数')", 3000);//模仿耗时操作
}
//调用主函数,将函数B传进去
A(B);

这里有一个问题,我们执行A函数后,执行B函数,为什么不直接在A函数里调用,要传参过去呢?

代码语言:javascript
复制
function A(callback) {
 B();
  console.log('我是主函数');
}

function B(){
  setTimeout("console.log('我是回调函数')", 3000);//模仿耗时操作
}

这段代码的作用和回调函数好像是一样的。其实这两种方法在性能上是没有区别的,只是在灵活性上有很大的区别。 例如,我定义了一个C函数为回调函数。

代码语言:javascript
复制
//定义主函数,回调函数作为参数
function A(callback) {
  callback();
  console.log('我是主函数');
}
//定义回调函数
function B(){
  setTimeout("console.log('我是回调函数')", 3000);//模仿耗时操作
}
//调用主函数,将函数B传进去
function C(){
  setTimeout("console.log('我是回调函数')", 3000);//模仿耗时操作
}
//调用主函数,将函数C传进去
A(B);
A(C);

这时候,在试一下这段代码,就会出现很大的分歧。

代码语言:javascript
复制
function A(callback) {
 B();
 C();
  console.log('我是主函数');
}

function B(){
  setTimeout("console.log('我是回调函数')", 3000);//模仿耗时操作
}
function C(){
  setTimeout("console.log('我是回调函数')", 3000);//模仿耗时操作
}

过滤器(filter)

这是另一种高阶函数,老样子,先看一下代码。

代码语言:javascript
复制
 array.filter(function(currentValue,index,arr), thisValue)

filter 接收一个函数作为参数,所以它也符合高阶函数中的第一个定义,作为参数被传递。

那什么是filter呢? filter()方法会创建一个新数组,原数组的每个元素传入回调函数中,回调函数中有return返回值,若返回值为true,这个元素保存到新数组中;若返回值为false,则该元素不保存到新数组中;原数组不发生改变。

简单来说,filter就是一个过滤数组的方法,符合条件的被传入新的数组,不符合条件的,就不管它了。

举个例子:

在一个Array中,删掉偶数,只保留奇数,可以这么写:

代码语言:javascript
复制
 var arr = [1, 2, 4, 5, 6, 9, 10, 15];
 var r = arr.filter(function (x) {
     return x % 2 !== 0;
 });
 r; // [1, 5, 9, 15]

定义了arr这个数组,arr数组使用的过滤器,过滤器中函数的作用就是把数组中的偶数过滤出来,放进r数组中。

使用filter,注意两点,1.filter() 不会对空数组进行检测;2. filter() 不会改变原始数组。

过滤器很强大,比如,我们面试经常会考的数组去重:

代码语言:javascript
复制
'use strict';
 
 var r,arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
   r = arr.filter(function (element, index, self) {
      return self.indexOf(element) === index;
   });
 console.log(r.toString()); //apple,strawberry,banana,pear,orange

map

map()方法定义在JavaScript的Array中,它返回一个新的数组,数组中的元素为原始数组调用函数处理后的值。

注意: 1.map()不会对空数组进行检测;2.map()不会改变原始数组。

来看一看map的示例:

代码语言:javascript
复制
function pow(x){
    return x*x;
}
var arr = [1,2,3,4,5,6];
var results = arr.map(pow);
console.log(results);      //[1,4,9,16,25,36]

定义了一个pow函数,函数的做用是让参数平方,map函数的参数是pow参数,map遍历了数组,把数组的每一项传进了pow函数里面,再return出来。

map也是一个典型的高阶函数。

总结:

高阶函数就只讲这两个方法了,我相信以各位的聪明才智已经理解了什么是高阶函数。

最后留一个小思考,闭包,是不是高阶函数呢?

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 回调函数(callback)
  • 过滤器(filter)
  • map
  • 总结:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档