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
})
}
我们写一个可以复用的map变换函数,就像之前我们的可复用比较函数一样。让我们写一个叫做lookup 的函数。 function lookup(obj, key) {
return obj[key]
}
// == [{name:"bob"}, {name:"john"}]
function friends(usersById, user) {
return user.friendIds.map(apply(lookup, usersById))
}
很接近要求,但我们需要的是名称,而不是friend对象本身。如果我们再写一个参数颠倒过来的lookup 函数,通过第二次的map可以把它们的名称取出来。 function lookupFlipped(key, obj) {
return lookup(obj, key)
}
// == ["bob", "john"]
function friendsNames(usersById, user) {
return friends(usersById, user)
.map(apply(lookupFlipped, "name"))
}
但是我不想定义这个lookupFlipped 函数,这样干有点傻。这样,我们来定义一个函数,它接收参数的顺序是从右到左,而不是从左到右,于是我们就能够复用lookup 了。 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") 函数返回的函数只接受一个参数——那个对象——返回对象的名称。我们不再需要反转任何东西:我们可以按任何顺序接受参数。
偏函数用法需要对一些常见的功能定义各种不同的函数,就像lt 函数,但这正是我们的目的。你可以以偏函数用法把lt 函数既用于count 函数,也可用于Array.filter 函数。它们可以复用,可以组合使用。 |