javascript for 循环的功能/声明版本(用这个例子)?

javascript functional / declarative version of for loop (with this example)?

有这个代码

const myMagic = (one, two, three, four) => `this is ${one} and ${two} and ${three} and ${four} as usual`

const txt = 'HELLO&ho&hy&hu&hq&HELLO&ho&hy&hu&hq&HELLO&ho&hy&hu&hq&HELLO&ho&hy&hu&hq&hx'
const fragments = txt.split('&')
const pieces = []

for (let i=0; i<fragments.length-1;i +=5) {
  pieces.push(fragments[i])
  pieces.push(myMagic(fragments[i+1],fragments[i+2],fragments[i+3],fragments[i+4]))
}

pieces.push(fragments[fragments.length-1])

console.log(pieces)

我怎样才能把它变成一个更具声明性的版本?

代码是这样的,因为拆分采用的正则表达式仅解析一次文本,然后使用这些片段,我根据需要使用 myMagic 函数

构建尽可能多的组件

那么有没有什么方法可以在不改变逻辑的情况下以更具声明性的方式编写它?

你总是可以使用递归函数来遍历列表:

const myMagic = (one, two, three, four) => `this is ${one} and ${two} and ${three} and ${four} as usual`

function pieces([zero, ...rest]) {
    if (!rest.length)
        return [zero];
    const [one, two, three, four, ...more] = rest;
    return [zero, myMagic(one, two, three, four), ...pieces(more)];
}

const txt = 'HELLO&ho&hy&hu&hq&HELLO&ho&hy&hu&hq&HELLO&ho&hy&hu&hq&HELLO&ho&hy&hu&hq&hx';
console.log(pieces(txt.split('&')))

不过,我建议使用某种 chunk(5) 函数,并 flatMap 处理其结果。

如果你喜欢declarative/functional风格,何不试试ramda.js

let txt = 'HELLO A,1,2,3,4,HELLO B,a,b,c,d,HELLO C,x,y,z,w';
let fragments = txt.split(',');

const myMagic = (one, two, three, four) => `this is ${one} and ${two} and ${three} and ${four} as usual`

//

const convert = R.pipe(
    R.splitEvery(5),
    R.chain(
        R.juxt(R.pair(
            R.head,
            R.pipe(R.tail, R.apply(myMagic))
        ))
    )
)

//


console.log(convert(fragments))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>

对我来说,最棒的地方在于使用一些可以从 lodash、ramda 或任何其他 "functional" 库中获得的实用程序,但将 [ a, f(b, c, d, e) ] 逻辑保留在常规箭头函数中。 (可能是个人喜好)

要采取的步骤:

  • 将字符串拆分为一个字符串数组(我使用 split("&")
  • 将字符串数组拆分为包含 5 个字符串的数组 (chunk(5))
  • 在外部数组上调用 flatMap
  • 使用 ([ head, ...tail]) => [ head, f(...tail) ] 映射内部数组,其中 f 是您的 "magic" 函数

// Utils
const range = s => Array.from(Array(Math.floor(s)), (_, i) => i);
const chunk = n => xs => range(xs.length / n)
  .map(i => xs.slice(i * n, i * n + n));
const split = del => str => str.split(del);
const flatMap = f => xs => xs.flatMap(f);
const pipe = (...fs) => x => fs.reduce((y, f) => f(y), x);

// App
const myMagic = (one, two, three, four) => `this is ${one} and ${two} and ${three} and ${four} as usual`

const convert = pipe(
  split("&"),
  chunk(5),
  flatMap(([ head, ...tail ]) => [ head, myMagic(...tail) ])
);

// Run it
const input = "HELLO1&ho&hy&hu&hq&HELLO2&ho&hy&hu&hq&HELLO3&ho&hy&hu&hq&HELLO4&ho&hy&hu&hq&hx";

console.log(convert(input));

如果你喜欢这样的东西可能会有所帮助ramda

const data = 'HELLO&ho&hy&hu&hq&HELLO&ho&hy&hu&hq&HELLO&ho&hy&hu&hq&HELLO&ho&hy&hu&hq&hx'

const toString = ([head, a, b, c, d] = []) => [
  head,
  `this is ${a} and ${b} and ${c} and ${d} as usual`,
]

const magic = R.pipe(
  R.split('&'),
  R.splitEvery(5),
  R.map(toString),
  R.unnest,
  R.init, // to remove last malformed item
);

console.log(
  'result : ',
  magic(data),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>