JavaScript中的高阶函数:这是什么?

我们向您介绍Sukhjinder Arora发表在《 零碎 》上的文章的译文 。 深入了解JavaScript中的高阶函数以及该语言内置的其他一些函数。


图片来自NESA,来自Makers,来自Unsplash

学习JavaScript编程,您可能会遇到高阶函数的概念。 尽管这个概念似乎令人生畏,但实际上并没有那么复杂。

由于具有处理高阶函数的能力,JavaScript适用于函数式编程。

高阶函数在JavaScript中很常见。 如果您与他一起工作了一段时间,很可能您甚至没有意识到就使用了这些功能。

要全面了解高阶函数,您首先需要了解什么是函数编程和一等函数

提示 :重用JavaScript函数通常会导致重复。 为了避免这种情况,请使用Bit(GitHub) 。 您可以轻松地找到新功能,共享它们并以最小的管理更改将它们重新应用。 试试吧,不要害羞。

什么是函数式编程


在不赘述的情况下,函数式编程是这样一种编程,其中某些函数作为参数传递给其他函数,然后将第三个函数作为值返回。 在函数式编程中,我们考虑并使用函数进行操作。

函数式编程是用JavaScript,Haskell,Clojure,Scala和Erlang等语言完成的。

什么是一流的功能


在学习使用JavaScript时,您最有可能听说过,函数是一等公民。 事实是,在JavaScript中,就像任何其他函数式编程语言一样,函数是对象。

专门针对JavaScript的函数是一种特殊的对象( Function对象或函子)。 例如:

 function greeting() { console.log('Hello World'); } // Invoking the function greeting(); // prints 'Hello World' 

为了说明JavaScript中的函数是对象,我们可以执行以下操作:

 // We can add properties to functions like we do with objects greeting.lang = 'English'; // Prints 'English' console.log(greeting.lang); 

注意:尽管以上在JavaScript中都可以正常使用,但您不应滥用它。 您不能将随机属性分配给函子-最好使用常规对象。

在JavaScript中,您可以使用其他实体执行的所有操作(例如对象,字符串或数字)都适用于函数。 可以将它们作为参数传递给其他函数(然后称为回调函数或回调函数),将它们分配给变量,依此类推。 这就是为什么JavaScript函数被称为一流函数的原因。

将函数分配给变量


JavaScript允许您将函数分配给变量。 例如:

 const square = function(x) { return x * x; } // prints 25 square(5); 

它们也可以被传输。 例如:

 const foo = square; // prints 36 foo(6); 

将函数作为参数传递


我们可以将函数作为参数传递给其他函数。 例如:

 function formalGreeting() { console.log("How are you?"); } function casualGreeting() { console.log("What's up?"); } function greet(type, greetFormal, greetCasual) { if(type === 'formal') { greetFormal(); } else if(type === 'casual') { greetCasual(); } } // prints 'What's up?' greet('casual', formalGreeting, casualGreeting); 

因此,既然我们知道什么是一流的函数,那么让我们来看一下JavaScript中的高阶函数。

高阶函数


高阶函数是与其他函数一起使用的函数,以一个函数作为参数,或者返回一个函数作为结果。

该语言已内置的高阶函数的示例是Array.prototype.mapArray.prototype.filterArray.prototype.reduce

高阶函数的作用


让我们看一些高阶内置函数的示例,并将它们与不使用高阶函数的解决方案进行比较。

Array.prototype.map
map()方法创建一个新数组,并为初始数组的每个元素调用传递的函数。 map()方法获取回调函数的每个值,并使用这些值创建一个新数组。

传递给map()方法的回调函数采用三个参数: elementindexarray

考虑一些例子。

示例1
假设我们有一个数字数组,然后我们要从中创建一个新数组,其中初始数组中的每个数字都会加倍。 有无高阶函数如何解决这个问题?

没有高阶函数:

 const arr1 = [1, 2, 3]; const arr2 = []; for(let i = 0; i < arr1.length; i++) { arr2.push(arr1[i] * 2); } // prints [ 2, 4, 6 ] console.log(arr2); 

使用高阶map功能:

 const arr1 = [1, 2, 3]; const arr2 = arr1.map(function(item) { return item * 2; }); console.log(arr2); 

使用箭头功能可以使代码更短。

 const arr1 = [1, 2, 3]; const arr2 = arr1.map(item => item * 2); console.log(arr2); 

示例2
假设我们有一个包含几个人的出生年数的数组,然后我们要从中创建一个新数组,以说明他们的年龄。

没有高阶函数:

 const birthYear = [1975, 1997, 2002, 1995, 1985]; const ages = []; for(let i = 0; i < birthYear.length; i++) { let age = 2018 - birthYear[i]; ages.push(age); } // prints [ 43, 21, 16, 23, 33 ] console.log(ages); 

使用高阶map功能:

 const birthYear = [1975, 1997, 2002, 1995, 1985]; const ages = birthYear.map(year => 2018 - year); // prints [ 43, 21, 16, 23, 33 ] console.log(ages); 

Array.prototype.filter
filter()方法创建一个新数组,其中所有元素都通过了传递函数中指定的测试。 传递给filter()的回调函数采用三个参数: elementindexarray

考虑一些例子。

示例1
想象一下,我们有一个包含对象的数组,这些对象的属性为“名称”和“年龄”。 从中我们想创建一个新的数组,其中仅指示成年人(18岁及以上)。

没有高阶函数:

 const persons = [ { name: 'Peter', age: 16 }, { name: 'Mark', age: 18 }, { name: 'John', age: 27 }, { name: 'Jane', age: 14 }, { name: 'Tony', age: 24}, ]; const fullAge = []; for(let i = 0; i < persons.length; i++) { if(persons[i].age >= 18) { fullAge.push(persons[i]); } } console.log(fullAge); 

使用高阶filter功能:

 const persons = [ { name: 'Peter', age: 16 }, { name: 'Mark', age: 18 }, { name: 'John', age: 27 }, { name: 'Jane', age: 14 }, { name: 'Tony', age: 24}, ]; const fullAge = persons.filter(person => person.age >= 18); console.log(fullAge); 

Array.prototype.reduce
reduce方法将一个函数应用于数组的每个值,将其简化为单个值。 reduce方法有两个参数:
  1. 要处理的回调函数;
  2. 可选的initialValue参数(第一个函数调用的第一个参数)。

回调函数采用四个参数: accumulatorcurrentValuecurrentIndexsourceArray

如果传递了initialValue参数,则accumulator参数将等于initialValue参数,而currentValue参数currentValue成为数组的第一个元素。

如果未传递initialValue参数,则accumulator参数将等于数组的第一个元素,而数组的第二个元素将被当作currentValue参数。

示例1
假设我们需要找到一个数组中数字的总和。

使用高阶函数reduce

 const arr = [5, 7, 1, 8, 4]; const sum = arr.reduce(function(accumulator, currentValue) { return accumulator + currentValue; }); // prints 25 console.log(sum); 

每次将回调函数应用于数组中的每个值时, accumulator参数都会保存该函数返回的上一个操作的结果,而currentValue将使用数组的下一个值。 完成后,结果存储在变量sum

另外,我们可以向该函数传递初始值:

 const arr = [5, 7, 1, 8, 4]; const sum = arr.reduce(function(accumulator, currentValue) { return accumulator + currentValue; }, 10); // prints 35 console.log(sum); 

没有高阶函数:

 const arr = [5, 7, 1, 8, 4]; let sum = 0; for(let i = 0; i < arr.length; i++) { sum = sum + arr[i]; } // prints 25 console.log(sum); 

如您所见,借助高阶函数,可以使代码更整洁,更短且功能更丰富。

创建自己的高阶函数


到目前为止,我们已经考虑了该语言内置的各种高阶函数。 是时候创建自己的高阶函数了。

想象一下,JavaScript将没有自己的map方法。 我们可以自己构建它,从而创建我们自己的高阶函数。

假设我们有一个字符串数组,然后我们要从中创建一个整数数组,其中每个元素都将代表初始数组中字符串的长度。

 const strArray = ['JavaScript', 'Python', 'PHP', 'Java', 'C']; function mapForEach(arr, fn) { const newArray = []; for(let i = 0; i < arr.length; i++) { newArray.push( fn(arr[i]) ); } return newArray; } const lenArray = mapForEach(strArray, function(item) { return item.length; }); // prints [ 10, 6, 3, 4, 1 ] console.log(lenArray); 

在上面的示例中,我们创建了一个高阶函数mapForEach ,它使用一个数组和一个回调函数fn作为参数。 此函数循环应用于数组的每个元素,并在每次迭代中将fn回调函数作为newArray.push函数newArray.push一部分进行newArray.push

fn回调函数采用初始数组的当前元素,并返回此元素的长度值,该值存储在新的newArray内部。 迭代完成后,将newArray数组作为结果返回并分配给lenArray数组。

结论


我们了解了什么是高阶函数,并研究了该语言内置的一些函数。 我们还学习了如何创建自己的高阶函数。

简而言之,高阶函数的工作方式与常规函数类似,但是具有将其他函数作为参数接收并作为结果返回的附加功能。

实际上,仅此而已。 如果您发现这篇文章对您有所帮助,也可以在MediumTwitter上关注我。 如有任何疑问,请随时发表评论! 我很乐意提供帮助。 :)

Source: https://habr.com/ru/post/zh-CN428612/


All Articles