仅当对象存在时使用 Ramda 调用对象的嵌套方法

Call nested methods on object only if it exists using Ramda

我目前有一个 user 对象,其中有一个 currentRoom() 方法,有时可能不存在或 return null.

如果 currentRoom() 方法 return 是什么东西,那么我需要对其调用 messages() 方法。如果两者都没有 returned,我想 return 一个默认的空数组 []

我想使用 Ramda 在功能上解决这个问题,因为它很简洁且可重用。目前,我的(非 Ramda)代码如下所示:

const user = Users.findOne({ username: params.id })
const room = (user.currentRoom && user.currentRoom() || {})
const messages = (room.messages && room.messages() || [])

我想的某种逻辑是传递所需方法的列表,如果没有任何结果,则传递默认结果。

/* getMessages(defaultIfNull, methodsArray, object) */

getMessages([], ['currentRoom', 'messages'], user)

基本上有点类似于pathOr,但是对象的方法。

我想我会像 Option:

一样使用 List monad
const getRoom = user => "currentRoom" in user ? [user.currentRoom()] : [];
const getMessages = room => "messages" in room ? room.messages() : [];

const allTogether = R.compose(R.chain(getMessage), R.chain(getRoom), R.of);
console.log(allTogether(Users.findOne({ username: params.id })));

您可以使用仅使用 Ramda 的无点解决方案。首先,我们定义一个 withDefaults 函数,它将在未定义这些方法的对象中设置 currentRoommessages 方法。

var withDefaults = R.pipe(

    // if don't have `currentRom` add a
    // `currentRom` function that returns an empty object
    R.unless(
        R.hasIn('currentRoom'), 
        R.assoc('currentRoom', 
            R.always({}))), 

    // if don't have `messages` add a
    // `messages` function that returns an empty array
    R.unless(
        R.hasIn('messages'), 
        R.assoc('messages', 
            R.always([]))))

此功能根据需要过滤对象设置方法。使用示例。

var user = withDefaults(getById(id))

接下来,定义一个 getter 函数来从对象中获取房间和消息。 invoker 是这个片段的核心部分,它 returns 一个调用方法的函数。参见 http://ramdajs.com/docs/#invoker

var getCurrentRoom = R.invoker(0, 'currentRoom')
var getMessages = R.invoker(0, 'messages')

以上代码可以如下使用。

var userWithRoom = withDefaults({
        currentRoom : function () {
            return {
                number : '123'
            }
        }
    })

var userWithMessages = withDefaults({
        messages : function () {
            return [
                'get lunch'
            ]
        }
    })

var userWithAll = withDefaults({
        currentRoom : function () {
            return {
                number : '123'
            }
        },
        messages : function () {
            return [
                'get lunch'
            ]
        }
    })

var userWithNone = withDefaults({})

一起

var withDefaults = R.pipe(
    R.unless(
        R.hasIn('currentRoom'), 
        R.assoc('currentRoom', 
            R.always({}))), 
    R.unless(
        R.hasIn('messages'), 
        R.assoc('messages', 
            R.always([]))))

var getCurrentRoom = R.invoker(0, 'currentRoom')
var getMessages = R.invoker(0, 'messages')

// examples

var userWithRoom = withDefaults({
        currentRoom : function () {
            return {
                number : '123'
            }
        }
    })

var userWithMessages = withDefaults({
        messages : function () {
            return [
                'get lunch'
            ]
        }
    })

var userWithAll = withDefaults({
        currentRoom : function () {
            return {
                number : '123'
            }
        },
        messages : function () {
            return [
                'get lunch'
            ]
        }
    })

现在让我们使用 console.log 测试上面的代码,看看我们的解决方案是否按预期工作

console.log(getCurrentRoom(userWithRoom))
console.log(getCurrentRoom(userWithMessages))    
console.log(getCurrentRoom(userWithAll))    
console.log(getCurrentRoom(userWithNone))

console.log('---')

console.log(getMessages(userWithRoom))    
console.log(getMessages(userWithMessages))    
console.log(getMessages(userWithAll))    
console.log(getMessages(userWithNone))

输出应该是:

{ number: '123' }
{}
{ number: '123' }
{}
---
[]
[ 'get lunch' ]
[ 'get lunch' ]
[]