我如何将 ramda.js 与此代码一起使用?

How can i use ramda.js with this code?

我开始使用ramda,但是对ramda的功能实现有疑惑

此代码用于挂载一个 select 对象来查询 sequelize。

见代码:

const stringRequired = string => !!string.length
const numberRequired = number => Number.isInteger(number)

const validadeInput = (value, initial, validade) => (
  validade(value) ? value : initial
)

const input = (obj, key, initial, validade) => (
  typeof obj[key] !== 'undefined' ?
  validadeInput(obj[key], initial, validade) :
  initial
);

const addValue = (obj, key, value) => {
  const prop = {}
  prop[key] = value
  return Object.assign(obj, prop)
}

const addFilter = (obj, key, value, validate) => (
  validate(value) ? addValue(obj, key, value)
  : obj
)

const selector = (query = {}) => {
  const limit = input(query, 'limit', 10, numberRequired);
  const name = input(query, 'name', '', stringRequired);

  let select = {}

  select = addFilter(select, 'name', name, stringRequired);
  select = addFilter(select, 'limit', limit, numberRequired);

  return select
}

console.log(selector()); 
// { limit: 10 }
console.log(selector({ name: 'David Costa' })); 
// { limit: 10, name: 'David Costa' }
console.log(selector({ limit: 50 }));
// { limit: 50 }

或在 link

上查看演示

http://jsbin.com/zerahay/edit?js,console,output

我有点犹豫要不要简单地用翻译的代码块来回应,我对继续学习的建议是尝试用 Ramda 的函数一个一个地替换你已经拥有的函数。

抛开犹豫,下面提供了一个示例,说明您的代码在使用 Ramda 的各种函数时可能看起来像什么。

// The existing check for `!!string.length` allows for potential issues with
// arrays being passed in and incorrectly validating, so this will ensure the
// value is indeed a string before checking its length

const stringRequired = R.both(R.is(String), R.complement(R.isEmpty))

// `addFilter` produces a function that takes an object and uses the provided
// function to validate the value associated with the provided key if it exists
// otherwise using the provided `initial` value. If valid, an object containing
// the key and value will be returned, otherwise an empty object is returned.

const addFilter = (validate, initial, key) =>
  R.pipe(
    R.propOr(initial, key),
    R.ifElse(validate, R.objOf(key), R.always({}))
  )

// `selector` takes an object and passes it to each function generated by
// calling `addFilter`, merging the resulting objects together.

const selector = (q = {}) =>
  R.converge(R.merge, [
    addFilter(stringRequired, '', 'name'),
    addFilter(Number.isInteger, 10, 'limit')
  ])(q)

console.log(selector())
console.log(selector({ name: 'David Costa' }))
console.log(selector({ limit: 50 }))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

为什么?

我认为你需要考虑为什么你想把它转换成 Ramda (免责声明:我是 Ramda 作者)Ramda 是一个库,一个工具包。当它有助于清理您的代码或当它使您更容易理解问题及其解决方案时,请使用它。不用的时候不要用。

也就是说,我确实使用 Ramda 重构了它:

重构

我只是试着重构了一下。最后,我将所有辅助函数替换为一个包含条件列表的辅助函数,例如 ['limit', 10, numberRequired] 以创建等同于 selector.

的函数

一路上我确实使用了一些 Ramda 函数,但唯一提供实质性帮助的是 assoc,它从旧对象以及键和值创建了一个新对象。例如,使用 compose(Boolean, length)const stringRequired = string => !!string.length 更干净,但差别不大。

在我看来,重要的变化是 makeSelector 函数,它使创建 selector 函数更具声明性。它有点难看,如果我从头开始,我可能会写得不一样,但我是通过一系列步骤完成的,内联你的辅助函数,直到我有一个具有相同行为的相当短的函数。

// rules
const stringRequired = R.compose(Boolean, R.length)
const numberRequired = number => Number.isInteger(number)


// utils
const makeSelector = (conditions) => (query = {}) => R.reduce(
  (select, [key, initial, validate]) => {
    const value = key in select && validate(select[key]) ? select[key] : initial;
    return validate(value) ? R.assoc(key, value, select) : select
  },
  query,
  conditions
)

// main
const selector = makeSelector([
  ['limit', 10, numberRequired],
  ['name', '', stringRequired]
])

console.log(selector());
console.log(selector({ name: 'David Costa' }));
console.log(selector({ limit: 50 }));
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>