### 高阶函数(Higher Order Functions)

``````// 不灵活
function countMatching(array, value) {
var counted = 0
for (var i = 0; i < array.length; i++) {
if (array[i] == value)
counted++
}
return counted
}

// == 2
countMatching([1,3,3,4,5], 3)
``````

``````// more flexible
function count(array, matching) {
var counted = 0
for (var i = 0; i < array.length; i++) {
if (matching(array[i]))
counted++
}
return counted
}

// == 2, same as first example
count([1,3,3,4,5], function(num) {
return (num == 3)
})

// == 2, now we can use our functions for ANY kind of items or match test!
count([{name:"bob"}, {name:"henry"}, {name:"jon"}], function(obj) {
return (obj.name.length < 4)
})
``````

### 可重复利用的比较函数

``````function eq(a, b) {
return (a == b)
}

count([1,3,3,4,5], function(num) {
return eq(3, num)
})
``````

``````
function makeEq(a) {
// countMatchingWith wants a function that takes
// only 1 argument, just like the one we're returning
return function(b) {
return eq(a, b)
}
}

// now it's only on one line!
count([1,3,3,4,5], makeEq(3))
``````

### 偏函数用法(Partial Application)

``````function applyFirst(f, a) {
return function(b) {
return f.call(null, a, b)
}
}

count([1,3,3,4,5], applyFirst(eq, 3))
``````

``````function apply(f) {
var args = Array.prototype.slice.call(arguments, 1)
return function(x) {
return f.apply(null, args.concat(x))
}
}

function propertyEquals(propertyName, value, obj) {
return (obj[propertyName] == value)
}

count([{name:"bob"},{name:"john"}], apply(propertyEquals, "name", "bob")) // == 1
``````

### 配合ES5的 Map 和 Filter 功能函数的偏函数用法

ES5里有很多非常好的高阶函数，underscore里的数量更多。让我们看看`filter`函数——一个接收比较函数、过滤数组内容的函数。

``````// this equals [1,3,3]
[1,3,3,4,5].filter(function(num) {
return (num < 4)
})
``````

``````function lt(a, b) {
return (a < b)
}

[1,3,3,4,5].filter(apply(lt, 4))
``````

`map`函数能让你把数组里的一个东西变成另外一个东西。

``````var usersById = {"u1":{name:"bob"}, "u2":{name:"john"}}
var user = {name:"sean", friendIds: ["u1", "u2"]}

// == ["bob", "john"]
function friendsNames(usersById, user) {
return user.friendIds.map(function(id) {
return usersById[id].name
})
}
``````

``````function lookup(obj, key) {
return obj[key]
}

// == [{name:"bob"}, {name:"john"}]
function friends(usersById, user) {
return user.friendIds.map(apply(lookup, usersById))
}
``````

``````function lookupFlipped(key, obj) {
return lookup(obj, key)
}

// == ["bob", "john"]
function friendsNames(usersById, user) {
return friends(usersById, user)
.map(apply(lookupFlipped, "name"))
}
``````

``````function applyr(f) {
var args = Array.prototype.slice.call(arguments, 1)
return function(x) {
return f.apply(null, [x].concat(args))
}
}

// == ["bob", "john"]
function friendsNames(usersById, user) {
return friends(usersById, user)
.map(applyr(lookup, "name")) // we can use normal lookup!
}
``````

`applyr(lookup, "name")`函数返回的函数只接受一个参数——那个对象——返回对象的名称。我们不再需要反转任何东西：我们可以按任何顺序接受参数。

### 函数组合

``````function friendsNames(usersById, user) {
return user.friendIds.map(function(id) {
var friend = lookup(usersById, id)
return lookup(friend, "name")
})
}
``````

``````function compose(f, g) {
return function(x) {
return f(g(x))
}
}

function friendsNames(usersById, user) {
return user.friendIds.map(compose(applyr(lookup, "name"), apply(lookup, usersById)))
}
``````

``````var friend = lookup // lookup 恰巧能干我们想要的事情。
var name = applyr(lookup, "name")

function friendsNames(usersById, user) {
// this line is now more semantic.
return user.friends.map(compose(name, apply(friend, usersById)))
}
``````

### 函数式和功能单一化让你的代码库更整洁

1. 一种宽泛的组合。并不特指函数或对象组合，只是一种你用小东西组建大东西的思想。

2. “Matching functions”被称作predicates，但我这里不想引入新的编程术语。

3. 这里有更通用的`apply`实现。

[本文英文原文链接：Learn You a Haskell: For Great Good? ]

0

0

0

0

0

0

0

0
0

0