Skip to content

JavaScript 高阶函数

高阶函数

高阶函数是将其他函数作为参数或返回函数作为值的函数。作为参数传递的函数称为回调函数。

回调函数

回调函数是可以作为参数传递给其他函数的函数。请看下面的例子。

js
// 回调函数,函数名可以是任何名称
const callback = (n) => {
  return n ** 2
}

// 将其他函数作为回调的函数
function cube(callback, n) {
  return callback(n) * n
}

console.log(cube(callback, 3))

返回函数

高阶函数返回函数作为值

js
// 返回另一个函数的高阶函数
const higherOrder = n => {
  const doSomething = m => {
    const doWhatEver = t => {
      return 2 * n + 3 * m + t
    }
    return doWhatEver
  }
  return doSomething
}
console.log(higherOrder(2)(3)(10))

让我们看看在哪里使用回调函数。例如,forEach 方法使用回调。

js
const numbers = [1, 2, 3, 4, 5]
const sumArray = arr => {
  let sum = 0
  const callback = function(element) {
    sum += element
  }
  arr.forEach(callback)
  return sum
}
console.log(sumArray(numbers))
sh
15

上面的例子可以简化如下:

js
const numbers = [1, 2, 3, 4]

const sumArray = arr => {
  let sum = 0
  arr.forEach(function(element) {
    sum += element
  })
  return sum
}
console.log(sumArray(numbers))
sh
15

设置时间

在 JavaScript 中,我们可以在特定的时间间隔内执行某些活动,或者我们可以安排(等待)一段时间来执行某些活动。

  • setInterval
  • setTimeout

使用 setInterval 函数设置间隔

在 JavaScript 中,我们使用 setInterval 高阶函数在某个时间间隔内连续执行某些活动。setInterval 全局方法接受回调函数和持续时间作为参数。持续时间以毫秒为单位,回调将始终在该时间间隔内被调用。

js
// 语法
function callback() {
  // 代码在这里
}
setInterval(callback, duration)
js
function sayHello() {
  console.log('Hello')
}
setInterval(sayHello, 1000) // 每秒打印 hello,1000ms 是 1s

使用 setTimeout 设置时间

在 JavaScript 中,我们使用 setTimeout 高阶函数在将来的某个时间执行某些操作。setTimeout 全局方法接受回调函数和持续时间作为参数。持续时间以毫秒为单位,回调等待该时间量。

js
// 语法
function callback() {
  // 代码在这里
}
setTimeout(callback, duration) // 持续时间以毫秒为单位
js
function sayHello() {
  console.log('Hello')
}
setTimeout(sayHello, 2000) // 等待 2 秒后打印 hello

函数式编程

JavaScript 的最新版本引入了许多内置方法,可以帮助我们解决复杂的问题,而不是编写常规循环。所有内置方法都接受回调函数。在本节中,我们将看到 forEachmapfilterreducefindeverysomesort

forEach

forEach:迭代数组元素。我们只对数组使用 forEach。它接受一个带有元素、索引参数和数组本身的回调函数。索引和数组是可选的。

js
arr.forEach(function (element, index, arr) {
  console.log(index, element, arr)
})
// 上面的代码可以使用箭头函数编写
arr.forEach((element, index, arr) => {
  console.log(index, element, arr)
})
// 上面的代码可以使用箭头函数和显式返回编写
arr.forEach((element, index, arr) => console.log(index, element, arr))
js
let sum = 0;
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(num => console.log(num))
console.log(sum)
sh
1
2
3
4
5
js
let sum = 0;
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(num => sum += num)

console.log(sum)
sh
15
js
const countries = ['Finland', 'Denmark', 'Sweden', 'Norway', 'Iceland']
countries.forEach((element) => console.log(element.toUpperCase()))
sh
FINLAND
DENMARK
SWEDEN
NORWAY
ICELAND

map

map:迭代数组元素并修改数组元素。它接受一个带有元素、索引、数组参数的回调函数并返回一个新数组。

js
const modifiedArray = arr.map(function (element, index, arr) {
  return element
})
js
/*箭头函数和显式返回
const modifiedArray = arr.map((element,index) => element);
*/
//示例
const numbers = [1, 2, 3, 4, 5]
const numbersSquare = numbers.map((num) => num * num)

console.log(numbersSquare)
sh
[1, 4, 9, 16, 25]
js
const names = ['Asabeneh', 'Mathias', 'Elias', 'Brook']
const namesToUpperCase = names.map((name) => name.toUpperCase())
console.log(namesToUpperCase)
sh
['ASABENEH', 'MATHIAS', 'ELIAS', 'BROOK']
js
const countries = [
  'Albania',
  'Bolivia',
  'Canada',
  'Denmark',
  'Ethiopia',
  'Finland',
  'Germany',
  'Hungary',
  'Ireland',
  'Japan',
  'Kenya',
]
const countriesToUpperCase = countries.map((country) => country.toUpperCase())
console.log(countriesToUpperCase)

/*
// 箭头函数
const countriesToUpperCase = countries.map((country) => {
  return country.toUpperCase();
})
//显式返回箭头函数
const countriesToUpperCase = countries.map(country => country.toUpperCase());
*/
sh
['ALBANIA', 'BOLIVIA', 'CANADA', 'DENMARK', 'ETHIOPIA', 'FINLAND', 'GERMANY', 'HUNGARY', 'IRELAND', 'JAPAN', 'KENYA']
js
const countriesFirstThreeLetters = countries.map((country) =>
  country.toUpperCase().slice(0, 3)
)
sh
 ["ALB", "BOL", "CAN", "DEN", "ETH", "FIN", "GER", "HUN", "IRE", "JAP", "KEN"]

filter

filter:过滤出满足过滤条件的项目并返回一个新数组。

js
//过滤包含 land 的国家
const countriesContainingLand = countries.filter((country) =>
  country.includes('land')
)
console.log(countriesContainingLand)
sh
['Finland', 'Ireland']
js
const countriesEndsByia = countries.filter((country) => country.endsWith('ia'))
console.log(countriesEndsByia)
sh
['Albania', 'Bolivia','Ethiopia']
js
const countriesHaveFiveLetters = countries.filter(
  (country) => country.length === 5
)
console.log(countriesHaveFiveLetters)
sh
['Japan', 'Kenya']
js
const scores = [
  { name: 'Asabeneh', score: 95 },
   { name: 'Lidiya', score: 98 },
  { name: 'Mathias', score: 80 },
  { name: 'Elias', score: 50 },
  { name: 'Martha', score: 85 },
  { name: 'John', score: 100 },
]

const scoresGreaterEighty = scores.filter((score) => score.score > 80)
console.log(scoresGreaterEighty)
sh
[{name: 'Asabeneh', score: 95}, { name: 'Lidiya', score: 98 },{name: 'Martha', score: 85},{name: 'John', score: 100}]

reduce

reduce:reduce 接受一个回调函数。回调函数接受累加器、当前值和可选的初始值作为参数,并返回单个值。为累加器值定义初始值是一个好习惯。如果我们不指定此参数,默认情况下累加器将获得数组的第一个值。如果我们的数组是空数组,那么 JavaScript 将抛出错误。

js
arr.reduce((acc, cur) => {
  // 在返回值之前进行一些操作
 return 
}, initialValue)
js
const numbers = [1, 2, 3, 4, 5]
const sum = numbers.reduce((acc, cur) => acc + cur, 0)

console.log(sum)
js
15

every

every:检查所有元素在某一方面是否相似。它返回布尔值

js
const names = ['Asabeneh', 'Mathias', 'Elias', 'Brook']
const areAllStr = names.every((name) => typeof name === 'string') // 都是字符串吗?

console.log(areAllStr)
sh
true
js
const bools = [true, true, true, true]
const areAllTrue = bools.every((b) => b === true) // 都是 true 吗?

console.log(areAllTrue) // true
sh
true

find

find:返回满足条件的第一个元素

js
const ages = [24, 22, 25, 32, 35, 18]
const age = ages.find((age) => age < 20)

console.log(age)
js
18
js
const names = ['Asabeneh', 'Mathias', 'Elias', 'Brook']
const result = names.find((name) => name.length > 7)
console.log(result)
sh
Asabeneh
js
const scores = [
  { name: 'Asabeneh', score: 95 },
  { name: 'Mathias', score: 80 },
  { name: 'Elias', score: 50 },
  { name: 'Martha', score: 85 },
  { name: 'John', score: 100 },
]

const score = scores.find((user) => user.score > 80)
console.log(score)
sh
{ name: "Asabeneh", score: 95 }

findIndex

findIndex:返回满足条件的第一个元素的位置

js
const names = ['Asabeneh', 'Mathias', 'Elias', 'Brook']
const ages = [24, 22, 25, 32, 35, 18]

const result = names.findIndex((name) => name.length > 7)
console.log(result) // 0

const age = ages.findIndex((age) => age < 20)
console.log(age) // 5

some

some:检查某些元素在某一方面是否相似。它返回布尔值

js
const names = ['Asabeneh', 'Mathias', 'Elias', 'Brook']
const bools = [true, true, true, true]

const areSomeTrue = bools.some((b) =>  b === true)

console.log(areSomeTrue) //true
js
const areAllStr = names.some((name) => typeof name === 'number') // 都是字符串吗?
console.log(areAllStr) // false

sort

sort:sort 方法按升序或降序排列数组元素。默认情况下,sort() 方法将值作为字符串排序。这对字符串数组项目很有效,但对数字无效。如果数字值作为字符串排序,它会给我们错误的结果。Sort 方法修改原始数组。建议在开始使用 sort 方法之前复制原始数据。

排序字符串值

js
const products = ['Milk', 'Coffee', 'Sugar', 'Honey', 'Apple', 'Carrot']
console.log(products.sort()) // ['Apple', 'Carrot', 'Coffee', 'Honey', 'Milk', 'Sugar']
//现在原始 products 数组也被排序了

排序数字值

如您在下面的示例中所见,100 在按升序排序后排在第一位。Sort 将项目转换为字符串,由于 '100' 和其他数字比较,字符串 '100' 开头的 1 成为最小的。为了避免这种情况,我们在 sort 方法内部使用比较回调函数,它返回负数、零或正数。

js
const numbers = [9.81, 3.14, 100, 37]
// 使用 sort 方法对数字项目排序提供错误的结果。见下文
console.log(numbers.sort()) //[100, 3.14, 37, 9.81]
numbers.sort(function (a, b) {
  return a - b
})

console.log(numbers) // [3.14, 9.81, 37, 100]

numbers.sort(function (a, b) {
  return b - a
})
console.log(numbers) //[100, 37, 9.81, 3.14]

排序对象数组

每当我们对数组中的对象进行排序时,我们使用对象键进行比较。让我们看看下面的例子。

js
objArr.sort(function (a, b) {
  if (a.key < b.key) return -1
  if (a.key > b.key) return 1
  return 0
})

// 或

objArr.sort(function (a, b) {
  if (a['key'] < b['key']) return -1
  if (a['key'] > b['key']) return 1
  return 0
})

const users = [
  { name: 'Asabeneh', age: 150 },
  { name: 'Brook', age: 50 },
  { name: 'Eyob', age: 100 },
  { name: 'Elias', age: 22 },
]
users.sort((a, b) => {
  if (a.age < b.age) return -1
  if (a.age > b.age) return 1
  return 0
})
console.log(users) // 按升序排序
// [{…}, {…}, {…}, {…}]

🌕 你做得很好。永远不要放弃,因为伟大的事情需要时间。你刚刚完成了第9天的挑战,你在通往伟大的道路上前进了9步。现在为你的大脑和肌肉做一些练习。

💻 练习

练习:级别 1

js
const countries = ['Finland', 'Sweden', 'Denmark', 'Norway', 'IceLand']
const names = ['Asabeneh', 'Mathias', 'Elias', 'Brook']
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const products = [
  { product: 'banana', price: 3 },
  { product: 'mango', price: 6 },
  { product: 'potato', price: ' ' },
  { product: 'avocado', price: 8 },
  { product: 'coffee', price: 10 },
  { product: 'tea', price: '' },
]
  1. 解释 forEachmapfilterreduce 之间的区别。
  2. 在 forEach、map、filter 或 reduce 中使用回调函数之前定义它。
  3. 使用 forEach 在控制台记录 countries 数组中的每个国家。
  4. 使用 forEach 在控制台记录 names 数组中的每个名字。
  5. 使用 forEach 在控制台记录 numbers 数组中的每个数字。
  6. 使用 map 通过将 countries 数组中的每个国家更改为大写来创建新数组。
  7. 使用 map 从 countries 数组创建国家长度数组。
  8. 使用 map 通过将 numbers 数组中的每个数字更改为平方来创建新数组
  9. 使用 map 将 names 数组中的每个名字更改为大写
  10. 使用 map 将 products 数组映射到其相应的价格。
  11. 使用 filter 过滤出包含 land 的国家。
  12. 使用 filter 过滤出有六个字符的国家。
  13. 使用 filter 过滤出在 country 数组中包含六个字母及以上的国家。
  14. 使用 filter 过滤出以 'E' 开头的国家;
  15. 使用 filter 过滤出只有值的价格。
  16. 声明一个名为 getStringLists 的函数,它接受一个数组作为参数,然后返回一个只包含字符串项的数组。
  17. 使用 reduce 对 numbers 数组中的所有数字求和。
  18. 使用 reduce 连接所有国家并产生这个句子:Estonia, Finland, Sweden, Denmark, Norway, and IceLand are north European countries
  19. 解释 someevery 之间的区别
  20. 使用 some 检查 names 数组中是否有一些名字的长度大于七
  21. 使用 every 检查所有国家是否都包含单词 land
  22. 解释 findfindIndex 之间的区别。
  23. 使用 find 在 countries 数组中找到第一个只包含六个字母的国家
  24. 使用 findIndex 在 countries 数组中找到第一个只包含六个字母的国家的位置
  25. 使用 findIndex 找到 Norway 的位置,如果它在数组中不存在,你将得到 -1。
  26. 使用 findIndex 找到 Russia 的位置,如果它在数组中不存在,你将得到 -1。

练习:级别 2

  1. 通过链接两个或多个数组迭代器找到产品的总价格(例如 arr.map(callback).filter(callback).reduce(callback))
  2. 仅使用 reduce 找到产品价格的总和 reduce(callback))
  3. 声明一个名为 categorizeCountries 的函数,它返回具有某些共同模式的国家数组(你在此存储库中找到 countries 数组作为 countries.js(例如 'land'、'ia'、'island'、'stan'))。
  4. 创建一个函数,返回一个对象数组,这是字母和字母用于以国家名称开头的次数。
  5. 声明一个 getFirstTenCountries 函数并返回十个国家的数组。使用不同的函数式编程在 countries.js 数组上工作
  6. 声明一个 getLastTenCountries 函数,它返回 countries 数组中的最后十个国家。
  7. 找出哪个字母作为国家名称的首字母使用了很多次(例如 Finland、Fiji、France 等)

练习:级别 3

  1. 使用 data 文件夹中的 countries 信息。按名称、首都、人口对国家进行排序

  2. *** 找到 10 种最常用的语言:

    js
    // 你的输出应该看起来像这样
    console.log(mostSpokenLanguages(countries, 10))
    [
    {country: 'English',count:91},
    {country: 'French',count:45},
    {country: 'Arabic',count:25},
    {country: 'Spanish',count:24},
    {country:'Russian',count:9},
    {country:'Portuguese', count:9},
    {country:'Dutch',count:8},
    {country:'German',count:7},
    {country:'Chinese',count:5},
    {country:'Swahili',count:4}
    ]
    
    // 你的输出应该看起来像这样
    console.log(mostSpokenLanguages(countries, 3))
    [
    {country: 'English',count: 91},
    {country: 'French',count: 45},
    {country: 'Arabic',count: 25},
    ]
  3. *** 使用 countries_data.js 文件创建一个函数,创建十个人口最多的国家

    js
    console.log(mostPopulatedCountries(countries, 10))
    
    [
    {country: 'China', population: 1377422166},
    {country: 'India', population: 1295210000},
    {country: 'United States of America', population: 323947000},
    {country: 'Indonesia', population: 258705000},
    {country: 'Brazil', population: 206135893},
    {country: 'Pakistan', population: 194125062},
    {country: 'Nigeria', population: 186988000},
    {country: 'Bangladesh', population: 161006790},
    {country: 'Russian Federation', population: 146599183},
    {country: 'Japan', population: 126960000}
    ]
    
    console.log(mostPopulatedCountries(countries, 3))
    [
    {country: 'China', population: 1377422166},
    {country: 'India', population: 1295210000},
    {country: 'United States of America', population: 323947000}
    ]
  4. *** 尝试开发一个程序,计算样本的集中趋势测量(均值、中位数、众数)和变异性测量(范围、方差、标准差)。除了这些测量之外,还要找到样本的最小值、最大值、计数、百分位数和频率分布。你可以创建一个名为 statistics 的对象,并创建所有进行统计计算的函数作为 statistics 对象的方法。检查下面的输出。

    js
    const ages = [31, 26, 34, 37, 27, 26, 32, 32, 26, 27, 27, 24, 32, 33, 27, 25, 26, 38, 37, 31, 34, 24, 33, 29, 26]
    
    console.log('Count:', statistics.count()) // 25
    console.log('Sum: ', statistics.sum()) // 744
    console.log('Min: ', statistics.min()) // 24
    console.log('Max: ', statistics.max()) // 38
    console.log('Range: ', statistics.range() // 14
    console.log('Mean: ', statistics.mean()) // 30
    console.log('Median: ',statistics.median()) // 29
    console.log('Mode: ', statistics.mode()) // {'mode': 26, 'count': 5}
    console.log('Variance: ',statistics.var()) // 17.5
    console.log('Standard Deviation: ', statistics.std()) // 4.2
    console.log('Variance: ',statistics.var()) // 17.5
    console.log('Frequency Distribution: ',statistics.freqDist()) # [(20.0, 26), (16.0, 27), (12.0, 32), (8.0, 37), (8.0, 34), (8.0, 33), (8.0, 31), (8.0, 24), (4.0, 38), (4.0, 29), (4.0, 25)]
    sh
    console.log(statistics.describe())
    Count: 25
    Sum:  744
    Min:  24
    Max:  38
    Range:  14
    Mean:  30
    Median:  29
    Mode:  (26, 5)
    Variance:  17.5
    Standard Deviation:  4.2
    Frequency Distribution: [(20.0, 26), (16.0, 27), (12.0, 32), (8.0, 37), (8.0, 34), (8.0, 33), (8.0, 31), (8.0, 24), (4.0, 38), (4.0, 29), (4.0, 25)]

🎉 恭喜!🎉