九、高阶函数
定义:就是一个函数的参数是函数,或者返回值是函数,满足其中一个就是高阶函数
开闭原则:对扩展是开发的,对修改是封闭的
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>