高阶函数(Higher-Order Functions)
1
2
3
4
5
6
7
8
9
const forEach = ( array , fn ) => {
let i
for ( i = 0 ; i < array . length ; i ++ ) {
fn ( array [ i ])
}
}
let array = [ 1 , 2 , 3 ]
forEach ( array , ( data ) => console . log ( data ))
现在我们已经看到了如何创建和执行高阶函数。 一般来说,高阶函数通常用来抽象常见的问题。 换句话说,高阶函数只不过是定义抽象。
forEach本质上是遍历数组。 如何遍历JavaScript对象?遍历JavaScript对象具有以下步骤:
迭代给定对象的所有键。 确定键属于自己的对象。 如果步骤2为真,则获取键的值。 1
2
3
4
5
6
7
8
9
10
const forEachObject = ( obj , fn ) => {
for ( let prop in obj ) {
if ( obj . hasOwnProperty ( prop )) {
fn ( prop , obj [ prop ])
}
}
}
let object = { a : 1 , b : 2 }
forEachObject ( object , ( k , v ) => console . log ( k + ":" + v ))
让我们创建一个名为unless的函数,这是一个简单的函数,它需要一个断言(应该是true或false); 如果断言是假,则调用fn。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const forEach = ( array , fn ) => {
let i
for ( i = 0 ; i < array . length ; i ++ ) {
fn ( array [ i ])
}
}
const unless = ( predicate , fn ) => {
if ( ! predicate )
fn ()
}
forEach ([ 1 , 2 , 3 , 4 , 5 , 6 , 7 ], ( number ) => {
unless (( number % 2 ), () => {
console . log ( number , ' is even' )
})
})
在上述情况下,我们从数组列表中获取偶数。 如果我们要从0到100获得偶数的列表怎么办? 我们不能在这里使用(当然我们可以,如果我们有数组有[0,1,2 …..,100])。 我们来看看另一个叫做times的高阶函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
const unless = ( predicate , fn ) => {
if ( ! predicate )
fn ()
}
const times = ( times , fn ) => {
for ( let i = 0 ; i < times ; i ++ )
fn ( i )
}
times ( 20 , ( n ) => {
unless ( n % 2 , () => console . log ( n , 'is even' ))
})
现实世界中的高阶函数
every Function
通常作为JavaScript开发人员,我们需要检查内容数组是否是数字,自定义对象或其他内容。 我们通常写典型的循环方法来解决这些问题。 但是让我们把它们抽成一个叫做every函数。 每个函数都有两个参数:数组和函数。 它检查数组的所有元素是否被传递函数求值为true。ES6规格中, for..of循环可用于迭代数组元素
1
2
3
4
5
6
7
8
9
10
11
const every = ( arr , fn ) => {
let result = true ;
for ( const value of arr ) {
result = result && fn ( value )
}
return result
}
every ([ NaN , NaN , NaN ], isNaN ) // true
every ([ NaN , NaN , 4 ], isNaN ) // false
every 一个典型的高阶函数,易于实现,同时它也非常有用!
some Function
类似于every函数,我们也有一个称为some的函数。 some函数与every函数完全相反,如果数组中的任何一个元素对传递的函数返回true,那么some函数将返回true。 some函数也被称为any函数。 为了实现some函数,我们使用|| 而不是 &&
1
2
3
4
5
6
7
8
9
10
11
const some = ( arr , fn ) => {
let result = false ;
for ( const value of arr ) {
result = result || fn ( value )
}
return ( result )
}
console . log ( some ([ NaN , NaN , 4 ], isNaN )) // true
console . log ( some ([ 2 , 3 , 4 ], isNaN )) // false
sort Function
sort是JavaScript的Array原型中提供的内置函数。
1
2
3
var fruit = [ 'cherries' , 'apples' , 'bananas' ];
console . log ( fruit . sort ())
// ["apples", "bananas", "cherries"]
排序函数是一个高阶函数,它接受一个函数作为其参数,这将有助于排序函数来决定排序逻辑。
1
arr . sort ([ compareFunction ])
这里的compareFunction是可选的。 如果没有提供compareFunction,则通过将元素转换为字符串并以Unicode代码顺序对比字符串进行排序。 为了在执行排序时将元素与我们自己的逻辑进行比较,我们需要设计我们自己compareFunction。 我们可以感觉到排序函数的设计如此灵活,以便它可以对JavaScript世界中的任何数据进行排序,只要我们通过一个compareFunction。 排序功能是灵活的,由于高阶功能的本质!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const people = [
{ firstname : "aaFirstName" , lastname : "cclastName" },
{ firstname : "ccFirstName" , lastname : "aalastName" },
{ firstname : "bbFirstName" , lastname : "bblastName" }
]
// compare firstname
people . sort (( a , b ) => {
return ( a . firstname < b . firstname ) ? - 1 : ( a . firstname > b . firstname ) ? 1 : 0
})
// compare lastname
people . sort (( a , b ) => {
return ( a . lastname < b . lastname ) ? - 1 : ( a . lastname > b . lastname ) ? 1 : 0
})
我们的compareFunction的算法,可以做得更好吗? 我们可以将上述逻辑抽象成一个函数吗,而不是每次写比较函数? 正如你在上面的例子中看到的,我们写了两个函数,用于比较firstName和lastName几乎相同的重复代码。 我们用高阶函数来解决这个问题。 现在我们要设计的函数将不会以函数为参数,而是返回一个函数。 (记住HOC也可以返回一个函数)。
1
2
3
4
5
6
7
8
9
10
11
12
13
const people = [
{ firstname : "aaFirstName" , lastname : "cclastName" },
{ firstname : "ccFirstName" , lastname : "aalastName" },
{ firstname : "bbFirstName" , lastname : "bblastName" }
]
const sortBy = ( property ) => {
return ( a , b ) => {
return ( a [ property ] < b [ property ]) ? - 1 : ( a [ property ] > b [ property ]) ? 1 : 0
}
}
people . sort ( sortBy ( 'lastname' ))