2021-11-28

九、高阶函数

定义:就是一个函数的参数是函数,或者返回值是函数,满足其中一个就是高阶函数

开闭原则:对扩展是开发的,对修改是封闭的

1.定义计算器方法

function calc(num1,num2,callback){

    callback(num1,num2)

}

<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>高阶函数</title>

</head>

<body>

    <script>

        // 什么是高阶函数:就是一个函数的参数是函数,或者返回值是函数,满足其中一个就是高阶函数

        // 开闭原则:对扩展是开发的,对修改是封闭的

        // 定义一个计算器函数

        // 注意:callback参数,接收的是一个函数。

        function calc(num1,num2,callback){

            return callback(num1,num2)

        }

        // 定义一个加法运算

        let add = function(num1,num2){

            return num1 + num2

        }

        // 计算两个数,统一调用calc方法,具体是如何计算,通过回调函数去实现。

        //先定义一个回调函数,在传进来

        let r1 = calc(300,100,add)

        console.log(r1);

        //回调函数可以直接调用时定义

        let r2 = calc(300,100,function(num1,num2){return num1 - num2})

        console.log(r2);

        //通常情况下,回调函数都会写成箭头函数的形式

        let r3 = calc(300,100, (num1,num2)=>num1 * num2)

        console.log(r3);

        let r4 = calc(300,100,(num1,num2)=>num1/num2)

        console.log(r4);

        let r5 = calc(16,6,(num1,num2)=>num1%num2)

        console.log(r5);

    </script>

</body>

</html>

2.回调函数

1.输出数组中所有的数    2.输出数组中所有的奇数    3.输出数组中所能被3整除的数

分析问题:都用到了for循环。定义一个通用的for方法:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>回调函数练习</title>

</head>

<body>

    <script>

        let arr = [11, 22, 33, 44, 55, 66, 77, 88, 99, 111, 222, 333, 444]

        //定义一个通用的$For函数,这个函数需要传两个参数:数组,回调函数

        function $For(arr, callback) {

            //循环数组

            for (let i = 0; i < arr.length; i++) {

                //调用回调函数callback,将数组中的每个数传进去,返回true,表示满足条件

                if (callback(arr[i])) {

                    console.log(arr[i]);

                }

            }

        }

        // 业务一:循环输出数组中所有的奇数

        // 定义一个函数,用于返回一个数是不是奇数

        function isJs(num) {

            return num % 2 !== 0

        }

        $For(arr, isJs)

        console.log('--------------------');

        // 业务二:循环输出数组中所有的偶数

        $For(arr, function (num) { return num % 2 === 0 })

        console.log('--------------------');

        // 业务三:循环输出数组中所有的能被3整除的数

        $For(arr, num => num % 3 === 0)

        console.log('--------------------');

        // 业务四:循环输出数组中所有的3位数

        $For(arr, num => num >= 100 && num < 1000)

    </script>

</body>

</html>

3.数组的高阶方法

1.forEach()方法,用于循环遍历整个数组。该方法的参数是一个回调函数,回调函数可以传两个参数,第一个参数是数组中的每一项元素,第二个参数是每一项元素对应的下标。注意:第二个参数可以省略。

2.filter()方法,用于过滤数组中的元素,返回过滤结果

3.find()方法,用于获取数组中满足规则的第一个元素

4.findIndex()方法,用于获取数组中满足规则的第一个元素下标

5.some()方法,用于表示数组中是否有满足指定规则的元素,有返回true,一个都没有返回false

6.every()方法,用于表示数组中是否所有元素都满足指定的规则

7.map()方法,用于将原始数组里面的数据根据指定的规则返回新的数组

8.sort()方法,对数组的元素进行排序。回调函数需要传两个参数,返回参数1-参数2是升序,返回参数2-参数1是降序

9.reduce()方法,统计数组中元素的值(从左到右)

10.reduceRight()方法,统计数组中元素的值(从右到左)

<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>数组的高阶方法</title>

</head>

<body>

    <script>

        let arr = [11,22,33,44,55,66,77,88,99,111,222,333,444]

        // 1.forEach()方法,用于循环遍历整个数组

        // forEach()方法的回调函数中,可以传两个参数:数组的每个元素 和 每一个元素对应的下标

        arr.forEach((val,index)=>console.log(index+'-'+val))

        // 2.filter()方法,用于过滤数组中的元素,返回过滤结果

        let arr1 = arr.filter(val => val % 2===0)

        console.log(arr1);

        let arr2 = arr.filter(val => val % 3===0)

        console.log(arr2);

        // 3.find()方法,用于获取数组中满足规则的第一个元素

        let num1 = arr.find(val=> val % 3===0)

        console.log(num1);

        // 4.findIndex()方法,用于获取数组中满足规则的第一个元素下标

        let index1 = arr.findIndex(val => val % 3===0)

        console.log(index1);

        // 5.some()方法,用于表示数组中是否有满足指定规则的元素,有返回true,一个都没有返回false

        let isHave1 = arr.some(val => val>1000)

        console.log(isHave1);

        let isHave2 =arr.some(val => val===222)

        console.log(isHave2);

        // 6.every()方法,用于表示数组中是否所有元素都满足指定的规则

        let isHave3 = arr.every(val => val > 10)

        console.log(isHave3);

        let isHave4 = arr.every(val => val % 2 ===0)

        console.log(isHave4);

        // 7.map()方法,用于将原始数组里面的数据根据指定的规则返回新的数组

        let arr3 = arr.map(r=>r%7)

        console.log(arr3);

        console.log('---------------------------------');

        let arr4 = [33,22,55,7,46]

        // 8.sort()方法,对数组的元素进行排序

        // 回调函数需要传两个参数,返回参数1 - 参数2是升序,返回参数2 - 参数1是降序

        console.log(arr4);

        arr4.sort((a,b)=>a-b)

        console.log(arr4);

        arr4.sort((a,b)=>b-a)

        console.log(arr4);

        // 9.reduce()方法,统计数组中元素的和(从左到右)

        // a是数组中的一个数,b从数组中第二个数开始,回调函数的返回值是a的下一次的值

        let sum1 = arr4.reduce((a,b)=>{

            return a+b

        })

        console.log(sum1);

        console.log('-------------------------------');

        // reduce()方法,可以给a设置一个起始值,这里的0就是a的起始值,b从数组的第一位开始。

        let sum2 = arr4.reduce((a,b)=>{

            return a+b

        },0)

        console.log(sum2);

        console.log('-------------------------------');

        // 10.reduceRight()方法,统计数组中元素的值(从右到左)

        let sum3 = arr4.reduceRight((a,b)=>{

            return a+b

        })

        console.log(sum3);

    </script>

</body>

</html>

4.闭包函数

定义一个a方法,在a方法中定义一个b方法,并且b方法里面用到了a方法里面定义的变量,那么此时就形成了闭包函数。由于内部方法里面,用到外部方法里面的变量,外部方法里面的那个变量会一直在内存中存保存着。

总结:两个方法嵌套定义,里面的方法,用到了外面方法里面定义的变量,此时这两个方法就形成了闭包。闭包案例:计算器

function calc(n1, n2, type) {

    // 数据定义在函数里面,用参数传值,保证了数据的安全性

    let num1 = n1

    let num2 = n2

    switch (type) {

        case '+':

            return function () {

                console.log(`${num1}+${num2}=${num1 + num2}`);

            }

        case '-':

            return function () {

                console.log(`${num1}-${num2}=${num1 - num2}`);

            }

    }

}

<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>闭包函数</title>

</head>

<body>

    <script>

        function a(){

            console.log('a函数被调用了...');

            let num1 = 100

            let num2 = 200

            function b(){

                console.log('b函数被调用了...');

                console.log(num1 + num2);

            }

            //返回的返回值也是一个函数,那么a函数,就是高阶函数。

            return b

        }

        // 通常情况下,函数执行完成后,函数里面定义的变量,会被销毁。

        // a函数,已经调用完毕了,但是a函数里面定义变量,始终在内存中,因为b函数中用到了a函数中定义的变量。

        // 那么此时这两个函数,就称之为:闭包函数。

        let c = a()

        c()

        console.log('------------------------------------------');

        // 闭包函数的实际案例

        function calc(num1,num2,type){

            switch(type){

                case '+':

                    console.log(`${num1}+${num2}=${num1+num2}`);

                    break;

                case '-':

                    console.log(`${num1}-${num2}=${num1-num2}`);

                    break;

            }

        }

        // 在实际开发中,我们在做num1和num2的计算之前,可能需要先做其他事情

        let num1 = 100

        let num2 = 50

        // 在做其他事情的过程中,我们的数据很有可能会被篡改。

        console.log('查看用户是否登录');

        num1 = 555

        num2 = 145

        console.log('检查用户的权限');

        calc(num1,num2,'+')  //运行结果不对,因为变量的值被篡改了。

        console.log('------------------------------------------');

        // 定义一个闭包函数,实现计算器功能

        function myCalc(num1,num2,type){

            switch(type){

                case '+':

                    return function(){

                        return num1 + num2

                    }

                case '-':

                    return function(){

                        return num1 - num2

                    }

            }

        }

        //先准备好你的数据

        let n1 = 100

        let n2 = 50

        //将你的数据传给计算器方法,由计算器方法,返回一个计算方法。

        let js = myCalc(n1,n2,'+')

        //在做具体的计算之前,还先做些其他的事情

        console.log('查看用户是否登录');

        n1 = 555

        n2 = 145

        console.log('检查用户的权限');

        //其他事件准备好了后,执行计算方法

        console.log(js());

    </script>

</body>

练习题:实现数组的高阶函数的原理:

1.forEach  2.filter  3.find  4.findIndex  5.some  6.ever  7.map  8.sort  9.reduce  10.reduceRight

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>实现数组的高阶函数的原理</title>

</head>

<body>

    <script>

        //forEach()用于循环遍历整个数组

        //该方法的参数是一个回调函数,回调函数可以传两个参数,第一个参数是数组中的每一项元素,

        //第二个参数是每一项元素对应的下标。

        //1.

        function myForEach(arr, callback) {

            for (let i = 0; i < arr.length; i++) {

                callback(arr[i], i)//不能加return,否则循环就执行一次

            }

        }

        let arr1 = [11, 22, 33, 44, 55, 66, 77, 88, 99]

        myForEach(arr1, (val, index) => console.log(`${val}-${index}`))

        //2.

        //filter()用于过滤数组中的元素,返回过滤结果

        function myFilter(arr, callback) {

            let arr2 = []

            for (let i = 0; i < arr.length; i++) {

                if (callback(arr[i])) {

                    arr2.push(arr[i])

                }

            }

            return arr2

        }

        let arr3 = myFilter(arr1, item => item % 2 === 0)

        console.log(arr3);

        //3.

        //find()用于获取数组中满足规则的第一个元素

        function myFind(arr, callback) {

            for (let i = 0; i < arr.length; i++) {

                if (callback(arr[i])) {

                    return arr[i]

                }

            }

        }

        console.log(myFind(arr1, item => item % 3 === 0));

        //4.

        //findIndex()用于获取数组中满足规则的第一个元素下标

        function myFindIndex(arr, callback) {

            for (let i = 0; i < arr.length; i++) {

                if (callback(arr[i])) {

                    return i

                }

            }

        }

        console.log(myFindIndex(arr1, item => item % 3 === 0));

        //5.

        //some()用于表示数组中是否有满足指定规则的元素,有返回true,一个都没有返回false

        function mySome(arr, callback) {

            for (let i = 0; i < arr.length; i++) {

                if (callback(arr[i])) {

                    return true

                }

            }

            return false

        }

        console.log(mySome(arr1, item => item % 10 === 0));

        //6.

        //every()用于表示数组中是否所有元素都满足指定的规则

        function myEvery(arr, callback) {

            for (let i = 0; i < arr.length; i++) {

                if (!callback(arr[i])) {

                    return false

                }

            }

            return true

        }

        console.log(myEvery(arr1, item => item > 10));

        //7.

        //map()用于将原始数组里面的数据根据指定的规则返回新的数组

        function myMap(arr, callback) {

            let arr4 = []

            for (let i = 0; i < arr.length; i++) {

                arr4.push(callback(arr[i]))

            }

            return arr4

        }

        console.log(myMap(arr1, item => item % 5));

        let arr5 = [22, 66, 88, 13, 45, 15, 89, 36]

        //8.

        //sort()对数组的元素进行排序,回调函数需要传两个参数,返回参数1 - 参数2是升序,返回参数2 - 参数1是降序

        function mySort1(arr, callback) {

            //外层循环表示比较的轮数

            for (let i = 0; i < arr.length - 1; i++) {

                //内层循环表示每轮比较的次数

                for (let j = 0; j < arr.length-1-i; j++) {

                    let result = callback(arr[j],arr[j+1])

                    if (result>0) {

                        let num = arr[j]

                        arr[j] = arr[j+1]

                        arr[j+1] = num

                    }

                }

            }

            return arr

        }

        console.log(mySort1(arr5, (a, b)=>a-b));

        function mySort2(arr, callback) {

            //外层循环表示比较的元素

            for (let i = 0; i < arr.length - 1; i++) {

                //内层的循环表示的是比较的数组元素

                for (let j = 1+i; j < arr.length; j++) {

                    let result = callback(arr[i],arr[j])

                    if (result>0) {

                        let num = arr[i]

                        arr[i] = arr[j]

                        arr[j] = num

                    }

                }

            }

            return arr

        }

        console.log(mySort2(arr5, (a, b)=>a-b));

        //9.

        //reduce()统计数组中元素的值(从左到右)

        function myReduce(arr, callback, sum) {

            for (let i = 0; i < arr.length; i++) {

                let sum1 = callback(sum, arr[i])

                sum = sum1//累加并赋值给sum

            }

            return sum

        }

        let s1 = myReduce(arr5, (a, b) => a + b, 10)

        console.log(s1);

        //10.

        //reduceRight()统计数组中元素的值(从右到左

        function myReduceRight(arr, callback, sum) {

            for (let i = arr.length - 1; i >= 0; i--) {

                let sum1 = callback(sum, arr[i])

                sum = sum1//累加并赋值给sum

            }

            return sum

        }

        let s2 = myReduceRight(arr5, (a, b) => a + b, 20)

        console.log(s2);

    </script>

</body>

</html>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容

  • 八、初识函数 1.定义 function 是定义函数的关键字,函数也称为方法 。 函数分为:1.无参函数 2.带...
    默默_01cf阅读 270评论 0 0
  • 十、函数补充以及初识对象 1.arguments arguments对象里面保存这方法的所有参数。argument...
    默默_01cf阅读 98评论 0 0
  • 七、Math和Date 1.排序算法 sort()方法,用于对数组排序。注意:该排序方法,是根据数组中,每一个元素...
    默默_01cf阅读 122评论 0 0
  • 回调函数概念: 函数的参数callback是另一个参数,这个参数在原始数据中执行 例如: let arr = ...
    锦衣夜行001阅读 421评论 0 1
  • 函数,即得到某种数据所需的方法,在JS(javascript后称JS)中,函数为封装的一段代码,用来求得期望数据的...
    青木樹海阅读 199评论 0 0