JS-13-高阶函数

一、高阶函数的定义

JavaScript的函数其实都指向某个变量,如:

var abs = function (x) {
    // 函数体
};

既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

示例:

function add(x, y, f) {
    return f(x) + f(y);
}

var x = add(-5, 6, Math.abs); // 11
console.log(x);

当我们调用add(-5, 6, Math.abs)时,推导计算过程为:

x = -5;
y = 6;
f = Math.abs;
f(x) + f(y) ==> Math.abs(-5) + Math.abs(6) ==> 11;
return 11;

二、高阶函数:Array.map

若,我们有一个函数f(x)=x2,要把这个函数作用在一个数组[1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map实现如下:

由于map()方法定义在JavaScript的Array中,我们调用Array的map()方法,传入我们自己的函数,就得到了一个新的Array作为结果:

function pow(x) {
    return x * x;
}

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
console.log(results);

【注意】:

Array.map(函数对象本身);

其实,写一个循环,也可以计算出结果: 

var f = function (x) {
    return x * x;
};

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var result = [];
for (var i=0; i<arr.length; i++) {
    result.push(f(arr[i]));
}

结果一样,但是,从上面的循环代码,我们无法一眼看明白“把f(x)作用在Array的每一个元素并把结果生成一个新的Array”。即:不直观。

所以,map()作为高阶函数,事实上它把运算规则抽象了。

同理,把Array的所有数字转为字符串,只需要一行代码:

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']

同理,把 Array的所有字符串转为数字,代码如下:

var strArray = ["1", "2", "3", "4", "5"];  
var intArray = strArray.map(Number);  
  
console.log(intArray); // 输出: [1, 2, 3, 4, 5]

2-1、parseInt函数

在JavaScript中,parseInt()函数用于将一个字符串解析成一个整数

它接收两个参数:要解析的字符串和基数(即数字的进制),基数可以是从2到36之间的整数。

如果省略基数参数,JavaScript会基于字符串的内容来猜测数字的基数。

// 解析十进制数  
let decimal = parseInt("10");  
console.log(decimal); // 输出: 10  
  
// 解析八进制数(以0开头)  
let octal = parseInt("010");  
console.log(octal); // 输出: 8,因为"010"在八进制中等于十进制的8  
  
// 解析十六进制数(以"0x"或"0X"开头)  
let hex = parseInt("0x10");  
console.log(hex); // 输出: 16,因为"0x10"在十六进制中等于十进制的16  
  
// 显式指定基数  
let num = parseInt("10", 2); // 将"10"解析为二进制数  
console.log(num); // 输出: 2,因为"10"在二进制中等于十进制的2  
  
// 如果字符串开头包含非数字字符,parseInt()会返回NaN  
let notANumber = parseInt("abc");  
console.log(notANumber); // 输出: NaN  
  
// 如果省略基数,且字符串以"0x"或"0X"开头,则假定为十六进制  
let assumedHex = parseInt("0xFF");  
console.log(assumedHex); // 输出: 255

注意,如果parseInt()的第一个参数不是一个字符串,它会被转换为字符串。如果,字符串的第一个字符不能被转换成数字,parseInt()会返回NaN

此外,如果基数参数不正确,或者超出了2到36的范围,parseInt()的行为可能因JavaScript引擎的实现而异,但通常会返回NaN

问题:小明希望利用map()把字符串变成整数,他写的代码如下:

var arr = ['1', '2', '3']; 
var r; 
r = arr.map(parseInt); 
console.log(r); // 1, NaN, NaN

结果是1, NaN, NaN,为什么?

小明遇到的这个问题是因为map()函数中的parseInt函数在调用时,会接受两个参数:

  • 第一个参数是要转换的字符串,
  • 第二个参数是基数(radix)。

当map()遍历数组时,它会将数组中的每个元素作为第一个参数传递给parseInt,同时将当前元素的索引(从0开始)作为第二个参数传递给parseInt

在parseInt函数中,第二个参数表示解析数字的基数。当基数不是预期的数值时(比如不是2到36之间的整数),parseInt可能无法正确解析字符串,导致返回NaN。

对应小明的代码:

1、对于arr[0](即字符串'1'),map()调用parseInt('1', 0),因为索引是0。

在parseInt中,基数为0时,如果字符串以"0x"或"0X"开头,会将其解析为十六进制数;否则,会将其解析为十进制数。因此,'1'被正确解析为整数1。

2、对于arr[1](即字符串'2'),map()调用parseInt('2', 1)。基数为1时,parseInt无法正确解析任何字符串,因此返回NaN。

3、对于arr[2](即字符串'3'),map()调用parseInt('3', 2)。基数为2时,'3'不是一个有效的二进制数字,因此parseInt返回NaN。

为了修正这个问题,小明应该确保map()函数中的回调函数只接受一个参数,即要转换的字符串。他可以通过箭头函数来明确指定只传递一个参数给parseInt:

        var arr = ['1', '2', '3'];
        var r;
        r = arr.map(numStr => parseInt(numStr, 10)); // r = arr.map(parseInt);  
        console.log(r); // [1, 2, 3]

三、高阶函数:Array.reduce

Array的reduce()把一个函数作用在这个Array的[x1, x2, x3...]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算,其效果就是:

[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)

示例1:对一个Array求和,就可以用reduce实现:

var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
    return x + y;
}); // 25

 如果数组元素只有1个,那么还需要提供一个额外的初始参数以便至少凑够两个参数:

var arr = [123];
arr.reduce(function (x, y) {
    return x + y;
}, 0); // 123

示例2:要把[1, 3, 5, 7, 9]变换成整数13579,reduce()也能派上用场:

var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
    return x * 10 + y;
}); // 13579

示例3:想办法把一个字符串13579先变成Array——[1, 3, 5, 7, 9],再利用reduce()就可以写出一个把字符串转换为Number的函数。

        var str = "13579";
        var arr = str.split('').map(Number);
        console.log(arr); // [1, 3, 5, 7, 9]

        var sum = arr.reduce(function (x, y){
            return x * 10 + y;
        });
        console.log(sum); //13579

示例4:利用reduce()求积:

        function product(arr){
            var res = arr.reduce(function (x, y) {
                return x * y;
            });
            return res;
        }

        // 测试:
        if (product([1, 2, 3, 4]) === 24 && product([0, 1, 2]) === 0 && product([99, 88, 77, 66]) === 44274384) {
            console.log('测试通过!');
        }
        else {
            console.log('测试失败!');
        }

四、高阶函数:Array.filter

filter也是一个常用的操作,它用于把Array的某些元素过滤掉,然后返回剩下的元素

和map()类似,Array的filter()也接收一个函数。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。

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

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]

把一个Array中的空字符串删掉,可以这么写:

var arr = ['A', '', 'B', null, undefined, 'C', '  '];
var r = arr.filter(function (s) {
    return s && s.trim(); // 注意:IE9以下的版本没有trim()方法
});
r; // ['A', 'B', 'C']

可见用filter()这个高阶函数,关键在于正确实现一个“筛选”函数。

4-1、回调函数

filter()接收的回调函数,其实可以有多个参数。通常我们仅使用第一个参数,表示Array的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身:

var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
    console.log(element); // 依次打印'A', 'B', 'C'
    console.log(index); // 依次打印0, 1, 2
    console.log(self); // self就是变量arr
    return true;
});

利用filter,可以巧妙地去除Array的重复元素:

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());

五、高阶函数:Array.sort

无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。

如果是数字,我们可以直接比较,但如果是字符串或者两个对象呢?比较的过程必须通过函数抽象出来。

通常规定,对于两个元素x和y,如果认为x < y,则返回-1,如果认为x == y,则返回0,如果认为x > y,则返回1,这样,排序算法就不用关心具体的比较过程,而是根据比较结果直接排序。

JavaScript的Array的sort()方法就是用于排序的,但是排序结果可能让你大吃一惊:

// 看上去正常的结果:
['Google', 'Apple', 'Microsoft'].sort(); // ['Apple', 'Google', 'Microsoft'];

// apple排在了最后:
['Google', 'apple', 'Microsoft'].sort(); // ['Google', 'Microsoft", 'apple']

// 无法理解的结果:什么鬼?简单的数字排序都能错?
[10, 20, 1, 2].sort(); // [1, 10, 2, 20]

第二个排序把apple排在了最后,是因为字符串根据ASCII码进行排序,而小写字母a的ASCII码在大写字母之后。

第三个数字排序的结果,真的是不能忍。

这是因为Array的sort()方法默认把所有元素先转换为String再排序,结果'10'排在了'2'的前面,因为字符'1'比字符'2'的ASCII码小。

sort()方法也是一个高阶函数,它还可以接收一个比较函数来实现自定义的排序。

要按数字大小排序,我们可以这么写:

        var arr = [10, 20, 1, 2];
        arr.sort(function (x, y) {
            if (x < y) {
                return -1;
            }
            if (x > y) {
                return 1;
            }
            return 0;
        });
        console.log(arr); // [1, 2, 10, 20]

倒序排序:

var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
    if (x < y) {
        return 1;
    }
    if (x > y) {
        return -1;
    }
    return 0;
}); // [20, 10, 2, 1]

默认情况下,对字符串排序,是按照ASCII的大小比较的。

现在,我们提出排序应该忽略大小写,按照字母序排序:

var arr = ['Google', 'apple', 'Microsoft'];
arr.sort(function (s1, s2) {
    x1 = s1.toUpperCase();
    x2 = s2.toUpperCase();
    if (x1 < x2) {
        return -1;
    }
    if (x1 > x2) {
        return 1;
    }
    return 0;
}); // ['apple', 'Google', 'Microsoft']

忽略大小写来比较两个字符串,实际上就是先把字符串都变成大写(或者都变成小写),再比较。

最后,sort()方法会直接对Array进行修改!!!

六、Array对象的其他高阶函数

对于数组,除了map()、reduce、filter()、sort()这些方法可以传入一个函数外,Array对象还提供了很多非常实用的高阶函数。

 

6-1、Array.every()

every() 是 JavaScript 的数组方法,它用于测试数组中的所有元素是否都通过了由提供的函数实现的测试。如果所有元素都通过测试,则返回 true;否则返回 false。

示例:假设我们有一个数组,我们想要检查数组中的所有数字是否都大于 10:

const numbers = [12, 5, 8, 130, 44];  
  
const allGreaterThanTen = numbers.every(function(num) {  
  return num > 10;  
});  
  
console.log(allGreaterThanTen); // 输出:false

在这个例子中,every() 方法会遍历 numbers 数组中的每个元素,并对每个元素执行提供的回调函数。由于 5 和 8 小于 10,所以 allGreaterThanTen 的值为 false。

6-2、Array.find()

find()方法用于查找符合条件的第一个元素,如果找到了,返回这个元素,否则,返回undefined。

var arr = ['Apple', 'pear', 'orange'];
console.log(arr.find(function (s) {
    return s.toLowerCase() === s;
})); // 'pear', 因为pear全部是小写

console.log(arr.find(function (s) {
    return s.toUpperCase() === s;
})); // undefined, 因为没有全部是大写的元素

 

6-3、Array.findIndex()

findIndex()和find()类似,也是查找符合条件的第一个元素,不同之处在于findIndex()会返回这个元素的索引,如果没有找到,返回-1:

var arr = ['Apple', 'pear', 'orange'];
console.log(arr.findIndex(function (s) {
    return s.toLowerCase() === s;
})); // 1, 因为'pear'的索引是1

console.log(arr.findIndex(function (s) {
    return s.toUpperCase() === s;
})); // -1

 

6-4、Array.forEach()

forEach()和map()类似,它也把每个元素依次作用于传入的函数,但不会返回新的数组。forEach()常用于遍历数组。

语法:

        var arr = ['Apple', 'pear', 'orange'];
        arr.forEach(function (currentValue, index, array){
            // currentValue:数组中正在处理的当前元素。
            // index(可选):数组中正在处理的当前元素的索引。
            // array(可选):forEach() 方法正在操作的数组。
        });

 

示例:假设我们有一个数组,并且我们想要打印出数组中的每个元素:

const array = [1, 2, 3, 4, 5];  
  
array.forEach(function(item, index) {  
  console.log(`Index: ${index}, Value: ${item}`);  
});

【注意】:

1、如果你需要基于原始数组创建一个新数组,那么你应该使用 map 方法。

2、forEach 不能在遍历过程中使用 break 或 continue 来中断或跳过迭代,如果你需要这样的控制流,你可能需要使用传统的 for 循环或其他迭代方法。 

使用传统的 for 循环遍历数组:

        const array = ['apple', 'banana', 'cherry', 'haha', 'clue'];

        for (let i = 0; i < array.length; i++) {
            if(array[i] === 'haha'){
                continue;
            }
            console.log(`Index: ${i}, Value: ${array[i]}`);
        }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/486627.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CCF-CSP认证考试 202212-2 训练计划 100分题解

更多 CSP 认证考试题目题解可以前往&#xff1a;CSP-CCF 认证考试真题题解 原题链接&#xff1a; 202212-2 训练计划 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 512.0MB 问题背景 西西艾弗岛荒野求生大赛还有 n n n 天开幕&#xff01; 问题描述 为了在大赛中取得…

shell实现查询进程号并批量kill(脚本)

问题或需求描述 在shell中&#xff0c;如果你想通过命令行查询出一系列匹配某个关键词的进程&#xff0c;并使用xargs命令批量结束这些进程&#xff0c;可以按照以下步骤操作&#xff1a; # 查询并提取进程号 pgrep -f "关键词" | xargs kill# 或者&#xff0c;如果…

Qt 用任意直线来分割多边形,返回分割后的多边形

任意直线分割多边形&#xff0c;返回分割后的多边形 效果 使用示例 QPolygonF LineSegmentationPolygon(const QPolygonF& poly, const QLineF& line, SideToRemove sideToRemove)源码 enum class SideToRemove {None,Left,Right};// 直线分割多边形 QPolygonF LineS…

多叉树题目:N 叉树的前序遍历

文章目录 题目标题和出处难度题目描述要求示例数据范围进阶 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 解法三思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;N 叉树的前序遍历 出处&#xff1a;589. N 叉树的前序遍历 难度 3 级 题目…

10-shell编程-辅助功能

一、字体颜色设置 第一种: \E[1:色号m需要变色的字符串\E[0m 第二种: \033[1:色号m需要变色的字符串\033[0m ########################### \E或者\033 #开启颜色功能 [1: #效果 31m #颜色色号 \E[0m #结束符 1&#xff0c;颜色案例 2&#xff0c;效果案例 二、gui&am…

波奇学Linux:网络接口

127.0.0.1本地回环ip&#xff0c;用于本地测试&#xff0c;不会进行网络通信 TCP是面向连接的&#xff0c;服务器比较被动 需要服套接字监听 listen状态 正常通信默认会进行主机序列和网络序列的转换 TcpServer.cc #pragma once#include<iostream> #include<string…

GAMES101 学习4

材质和外观 材质 BRDF 漫反射 任何方向的光进来都会被均匀的反射到周围各个不同的方向上去 假设能量守恒&#xff0c;那么 Li Lo&#xff0c;这之后BRDF就 &#xff0c;就可以定义一个反照率 &#xff08;Albeo&#xff09; - &#xff0c;在&#xff08;0 - 1&#xff0…

【包远程安装运行】SpringBoot+Mysql实现的图书商城平台+演示视频+开发文档(论文模板)

今天发布的是一款由SpringBootMySQL实现的在线图书商城系统源码&#xff0c;系统主要实现的功能分前台用户和后台管理。 前台功能主要有&#xff1a; 图书物展示、图书分类展示、图书搜索、用户登录注册、图书收藏、图书添加购物车、用户个人信息修改、用户充值提交、购物车图…

【Linux基础】ubuntu虚拟机配置及原理

一、虚拟机 虚拟机&#xff08;Virtual Machine&#xff0c;VM&#xff09;是一种软件实现的计算机系统&#xff0c;它在物理计算机上模拟了一个完整的计算机硬件环境&#xff0c;包括处理器、内存、存储设备和网络接口等。通过虚拟机&#xff0c;用户可以在单个物理计算机上同…

扭矩衰减的影响因素及改善措施——SunTorque智能扭矩系统

智能扭矩系统-智能拧紧系统-扭矩自动控制系统-SunTorque 扭矩衰减是许多机械系统中常见的问题&#xff0c;特别是在长期运行或高负荷工作环境下。扭矩衰减不仅影响设备的性能&#xff0c;还可能引发安全隐患。因此&#xff0c;了解扭矩衰减的影响因素及采取相应的改善措施至关…

Python Flask框架 -- ORM模型的CRUD操作(增删改查)

CRUD操作 使用ORM进行CRUD(Create、Read、Update、Delete)操作&#xff0c;需要先把操作添加到会话中&#xff0c;通过db.session可以获取到会话对象。会话对象只是在内存中&#xff0c;如果想要把会话中的操作提交到数据库中&#xff0c;需要调用db.session.commit()操作&…

Navicat Premium 16中文---数据库管理与开发的强大引擎

Navicat Premium 16是一款功能强大的数据库管理工具&#xff0c;旨在为用户提供高效、便捷的数据库连接、管理和保护体验。该软件支持多种数据库系统&#xff0c;如MySQL、Oracle、SQL Server等&#xff0c;满足用户多样化的需求。通过直观的图形界面&#xff0c;用户可以轻松进…

电脑中msvcp140_codecvt_ids.dll丢失的解决方法,实测有效的方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中最常见的就是缺少某个DLL文件。而msvcp140CODECVTIDS.dll就是其中之一。那么&#xff0c;msvcp140CODECVTIDS.dll是什么&#xff1f;msvcp140CODECVTIDS.dll文件属性又是什么呢&#xff1f;msvcp140C…

探索LLaMA模型:架构创新与Transformer模型的进化之路

引言 在人工智能和自然语言处理领域&#xff0c;预训练语言模型的发展一直在引领着前沿科技的进步。Meta AI&#xff08;前身为Facebook&#xff09;在2023年2月推出的LLaMA&#xff08;Large Language Model Meta AI&#xff09;模型引起了广泛关注。LLaMA模型以其独特的架构…

C语言例4-3:复合语句,输出a,b的值

代码如下&#xff1a; //复合语句&#xff0c;输出a,b的值 #include<stdio.h> int main(void) {int a 10;printf("a %d\n",a);{int b20; //复合语句printf("b %d\n",b); //复合语句中的数据定义语句放在其他语句的前面}return …

【每日力扣】332. 重新安排行程与51. N 皇后

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害。 332. 重新安排行程 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你…

急速解决代码扫描Mybatis的SQL注入问题

1.sql注入是什么 sql注入见名知意&#xff0c;是指一些非法用户通过将一些特殊字符或者sql语句插入到要提交的表单之中&#xff0c;从而让服务器在不知情的情况下执行恶意的sql命令&#xff0c;从而引发一系列的安全隐患。 讲的通俗一点就是说&#xff0c;用户利用sql语法将一…

java数据结构与算法刷题-----LeetCode75. 颜色分类

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 双指针两次遍历2. 三指针 1. 双指针两次遍历 解题思路&#…

数字化转型能给企业创造哪些价值?

企业数字化转型能创造哪些价值&#xff1f; 深耕TOB行业 9 年&#xff0c;下面来分享下自己的一些经验和看法。 &#xff08;看完要是觉得有用&#xff0c;记得点个赞哈~&#xff09; 1、从宏观上理解&#xff0c;我们可以分成4个大的方面&#xff1a; &#xff08;1&#x…

Linux操作系统及进程(三)进程优先级及特性

目录 一、优先级概念 二、查看系统进程 三、进程切换 一、优先级概念 1.cpu资源分配的先后顺序&#xff0c;就是指进程的优先权&#xff08;priority&#xff09;。 2.优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用&#xff0c;可以改善系统性能。…