Javascript 使用Ramdajs将命令式转换为函数式范式

Javascript 使用Ramdajs将命令式转换为函数式范式,javascript,functional-programming,lodash,ramda.js,Javascript,Functional Programming,Lodash,Ramda.js,下面的脚本创建了一个过滤一些输入数据的对象。 它使用多个嵌套的forEach以声明方式编码 我想知道在重写代码时使用哪个API,或者,特别是我想了解在本例中使用的是否合适 请举一个代码示例(特别是ramdajs)。谢谢 var数据={ “类型”:“样式表”, “样式表”:{ “规则”:[{ “类型”:“关键帧”, “名称”:“弹跳”, “关键帧”:[{ “类型”:“关键帧”, “价值观”:[ “从”, "20%", "53%", "80%", “到” ], “声明”:[{ “类型”:“声明”,

下面的脚本创建了一个过滤一些输入数据的对象。 它使用多个嵌套的
forEach
以声明方式编码

我想知道在重写代码时使用哪个API,或者,特别是我想了解在本例中使用的是否合适

请举一个代码示例(特别是ramdajs)。谢谢

var数据={
“类型”:“样式表”,
“样式表”:{
“规则”:[{
“类型”:“关键帧”,
“名称”:“弹跳”,
“关键帧”:[{
“类型”:“关键帧”,
“价值观”:[
“从”,
"20%",
"53%",
"80%",
“到”
],
“声明”:[{
“类型”:“声明”,
“属性”:“动画计时功能”,
“值”:“立方贝塞尔(0.215,0.610,0.355,1.000)”,
“职位”:{
“开始”:{
"行":3,,
“栏”:5
},
“结束”:{
"行":3,,
“栏”:72
}
}
}, {
“类型”:“声明”,
“属性”:“转换”,
“值”:“translate3d(0,0,0)”,
“职位”:{
“开始”:{
"行":4,,
“栏”:5
},
“结束”:{
"行":4,,
“栏”:34
}
}
}],
“职位”:{
“开始”:{
"线":2,,
“专栏”:3
},
“结束”:{
“行”:5,
“专栏”:4
}
}
}, {
“类型”:“关键帧”,
“价值观”:[
"40%",
"43%"
],
“声明”:[{
“类型”:“声明”,
“属性”:“动画计时功能”,
“值”:“立方贝塞尔(0.755,0.050,0.855,0.060)”,
“职位”:{
“开始”:{
“行”:8,
“栏”:5
},
“结束”:{
“行”:8,
“栏”:72
}
}
}, {
“类型”:“声明”,
“属性”:“转换”,
“值”:“translate3d(0,-30px,0)”,
“职位”:{
“开始”:{
“行”:9,
“栏”:5
},
“结束”:{
“行”:9,
“专栏”:40
}
}
}],
“职位”:{
“开始”:{
“行”:7,
“专栏”:3
},
“结束”:{
“行”:10,
“专栏”:4
}
}
}, {
“类型”:“关键帧”,
“价值观”:[
"70%"
],
“声明”:[{
“类型”:“声明”,
“属性”:“动画计时功能”,
“值”:“立方贝塞尔(0.755,0.050,0.855,0.060)”,
“职位”:{
“开始”:{
“行”:13,
“栏”:5
},
“结束”:{
“行”:13,
“栏”:72
}
}
}, {
“类型”:“声明”,
“属性”:“转换”,
“值”:“translate3d(0,-15px,0)”,
“职位”:{
“开始”:{
“行”:14,
“栏”:5
},
“结束”:{
“行”:14,
“专栏”:40
}
}
}],
“职位”:{
“开始”:{
“行”:12,
“专栏”:3
},
“结束”:{
“行”:15,
“专栏”:4
}
}
}, {
“类型”:“关键帧”,
“价值观”:[
"90%"
],
“声明”:[{
“类型”:“声明”,
“属性”:“转换”,
“值”:“translate3d(0,-4px,0)”,
“职位”:{
“开始”:{
“行”:18,
“栏”:5
},
“结束”:{
“行”:18,
“专栏”:37
}
}
}],
“职位”:{
“开始”:{
“行”:17,
“专栏”:3
},
“结束”:{
“行”:19,
“专栏”:4
}
}
}],
“职位”:{
“开始”:{
"线":一,,
“栏”:1
},
“结束”:{
“行”:20,
“专栏”:2
}
}
}, {
“类型”:“规则”,
“选择器”:[
“.bounce”
],
“声明”:[{
“类型”:“声明”,
“属性”:“动画名称”,
“值”:“反弹”,
“职位”:{
“开始”:{
“行”:23,
“专栏”:3
},
“结束”:{
“行”:23,
“栏”:25
}
}
}, {
“类型”:“声明”,
“属性”:“转换原点”,
“值”:“中间-底部”,
“职位”:{
“开始”:{
“行”:24,
“专栏”:3
},
“结束”:{
“行”:24,
“栏”:34
}
}
}],
“职位”:{
“开始”:{
“行”:22,
“栏”:1
},
“结束”:{
“行”:25,
“专栏”:2
}
}
}, {
“类型”:“关键帧”,
“名称”:“火花”,
“克
          transformAST
               ^
               |
               |
      getContentOfKeyframes
         ^              ^
         |              |
         |              |
  processKeyframe   processAnimation
var processKeyframe = (vals, declarations) => [
    // map each value
    R.map(R.cond([
        [R.equals('from'), R.always(0)],
        [R.equals('to'), R.always(100)],
        [R.T, parseFloat]
    ]), vals),
    // collect all property value pairs and merge in one object
    R.reduce(R.merge, {},
        R.map(R.converge(R.objOf, [
            R.prop('property'),
            R.prop('value')
        ]), declarations))
]
var processAnimation = (offsets, transf) => 
    R.map(R.pipe(
        R.objOf('offset'), 
        R.merge(transf)), offsets)
var getContentOfKeyframes = R.map(R.pipe(
    // process keyframes
    R.converge(processKeyframe, [
        R.prop('values'),
        R.prop('declarations')
    ]),
    // process animations
    R.converge(processAnimation, [
        R.nth(0),
        R.nth(1)
    ])))
var transformAST = R.pipe(
    // get `stylesheet.rules` property
    R.path(['stylesheet', 'rules']),
    // get only object whose `type` property is `keyframes`
    R.filter(R.propEq('type', 'keyframes')), 
    // map each item in `keyframes` collection
    // to an object {name: keyframe.name, content: [contentOfkeyframes] }
    R.map((keyframe) => ({
        name    : keyframe.name,
        content : getContentOfKeyframes(keyframe.keyframes)
    })),
    // finally make a new object using animation `name` as keys
    // and using a flatten content as values
    R.converge(R.zipObj, [
        R.map(R.prop('name')),
        R.map(R.pipe(R.prop('content'), R.flatten))
    ]))
var result = transformAST(data)
var processKeyframe = (vals, declarations) => [
    R.map(R.cond([
        [R.equals('from'), R.always(0)],
        [R.equals('to'), R.always(100)],
        [R.T, parseFloat]
    ]), vals),
    R.reduce(R.merge, {},
        R.map(R.converge(R.objOf, [
            R.prop('property'),
            R.prop('value')
        ]), declarations))
]

var processAnimation = (offsets, transf) => 
    R.map(R.pipe(
        R.objOf('offset'), 
        R.merge(transf)), offsets)

var getContentOfKeyframes = R.map(R.pipe(
    R.converge(processKeyframe, [
        R.prop('values'),
        R.prop('declarations')
    ]),
    R.converge(processAnimation, [
        R.nth(0),
        R.nth(1)
    ])))

var transformAST = R.pipe(
    R.path(['stylesheet', 'rules']),
    R.filter(R.propEq('type', 'keyframes')), 
    R.map((keyframe) => ({
        name    : keyframe.name,
        content : getContentOfKeyframes(keyframe.keyframes)
    })),
    R.converge(R.zipObj, [
        R.map(R.prop('name')),
        R.map(R.pipe(R.prop('content'), R.flatten))
    ]))

var result = transformAST(data)
const transform = pipe(
  path(['stylesheet', 'rules']),
  filter(where({'type': equals('keyframes')})),
  groupBy(prop('name')),
  map(map(kf => map(kfi => map(v => assoc('offset', cond([
      [equals('from'), always(0)],
      [equals('to'), always(100)],
      [T, parseFloat]
    ])(v), pipe(
        map(lift(objOf)(prop('property'), prop('value'))), 
        mergeAll
    )(kfi.declarations)), kfi.values), kf.keyframes)
  )),
  map(flatten)
);
{
  bounce: [obj1, obj2, ...]
  spark: [objA, objB, ...]
}
map(v => map(lift(objOf)(prop('property'), prop('value'))), kfi.declarations)
[
  {"animation-timing-function": "cubic-bezier(0.215, 0.610, 0.355, 1.000)",}
  {transform: "translate3d(0,0,0)"},
]
cond([
  [equals('from'), always(0)],
  [equals('to'), always(100)],
  [T, parseFloat]
])(v)
{
  "animation-timing-function": "cubic-bezier(0.215, 0.610, 0.355, 1.000)",
  offset: 0,
  transform: "translate3d(0,0,0)"
}
{
  bounce: [[[obj1, obj2, ...]]]
  spark: [[[objA, objB, ...]]]
}