Простое решение с использованием программирования функций «карри» для решения N уровней циклов.

Вам приходилось перебирать сложную структуру данных, чтобы получить результат?

Например, представьте, что вам нужно вызывать такие циклы:

for country in countries:
  for state in states:
    for city in cities:
      for school in schools:
        call_my_func(my_args)

Давайте попробуем решить простейшую ситуацию, предполагая, что у нас есть только один уровень, и нам просто нужно выполнить цикл следующим образом:

for (let i = 0; i < n; i++){
  console.log("hello", "world")
}

Если мы поместим его в функцию «карри», он должен выглядеть так:

function loop(n, func){
  return (...args) => {
    let i = 0
    while(i < n){
      func(...args)
      i ++
    }
  }
}
l3 = loop(3, (...arg)=> console.log(...arg))
l3("hello", "world")

Функция цикла возвращает функцию, которая просто выполнит цикл 3 раза и напечатает 3 строки «hello world».

Это не так уж и плохо, давайте улучшим его, чтобы он также мог использовать m уровень петель
Что-нибудь для имитации следующего

for (let i0 = 0; i0 < n; i0++){
  for (let i1= 0; i1 < n; i1++){
    for (let i2 = 0; i2 < n; i2++){
...
...
      for (let im = 0; im < n; im++){
         console.log("hello", "world")
}

Как мы решаем эту проблему? Нам нужен массив для хранения значений каждого i (i0, i1… im). Мы можем назвать это я []

Логика заключается в том, что сначала мы увеличиваем i [m], затем если i [m] ≥ n, то мы увеличиваем i [m-1] и продолжайте движение до тех пор, пока не станет i [0] ≥ n

Теперь переведем логику в код, это выглядит так

    // Create an m-items array and fill with 0
    let i = Array(m).fill(0)
    function inc(j){
      i[j] += 1
      if(i[j] >= n){
        if(j <= 0) return
        i[j] = 0
        inc(j - 1)
      }
    }

Функция inc (j) будет увеличиваться до тех пор, пока не станет больше, чем n, затем будет увеличиваться (j-1) до первого слоя (a [0]) ≥ n, затем рекурсивная функция возвращает

Теперь мы можем вернуться к нашему вопросу выше, чтобы реализовать функцию, которая может обрабатывать уровень циклов m.

function loop(n,m, func){
  return (...args) => {
    let i = Array(m).fill(0)
    function inc(j){
      i[j] += 1
      if(i[j] >= n){
        if(j <= 0) return
        i[j] = 0
        inc(j - 1)
      }
    }
    while(i[0] < n){
      func(...args)
      console.log(i)
      console.log()
      inc(m - 1)
    }
  }
}
l4 = loop(2,2, (...arg)=> console.log(...arg))
l4("hello", "world")

Приведенная выше функция напечатает такой результат

hello world
[ 0, 0 ]
hello world
[ 0, 1 ]
hello world
[ 1, 0 ]
hello world
[ 1, 1 ]

Вы можете попробовать с разными числами n, m, и в основном вы получите n ^ m (m степень n) строк «hello world» :)

Теперь мы накопили достаточно опыта, чтобы решить последний вопрос - перебрать произвольный массив «циклов».

[ "0:2:1",
  "0:4:2",
  "1:9:4" ]

Вышеупомянутый массив пытается представить такую ​​логику

for(let i0 = 0; i0 < 2; i0 ++)
  for(let i1 = 0; i1 < 4; i1 += 2)
    for(let i2 = 0; i2 < 9; i2 += 4)

Строки в массиве предназначены для имитации синтаксиса Python «Slice».

Slice означает, что первое число - это «начало», второе число - «конец», а третье число - «шаг» (шаг по умолчанию равен 1).

Вот и последняя версия решения, которое просто объединяет все, что у нас было до сих пор.

function loop(slices, func){
  return (...args) => {
    let m = slices.length
    let a = Array(m).fill({})
    for(let i = 0; i < m; i++ ){
      let [start, end, step] = slices[i].split(":").map(x => parseInt(x))
      step = step || 1
      a[i] = { start, end, step, cur: start }
    }
    function inc(j){
      a[j].cur += a[j].step
      if(a[j].cur >= a[j].end){
        if(j <= 0) return
        a[j].cur = a[j].start
        inc(j - 1)
      }
    }
    while(a[0].cur < a[0].end){
      func(...args)
      console.log(a)
      console.log()
      inc(m - 1)
    }
  }
}
l5 = loop([
  "0:2",
  "0:4:2",
  "1:9:4"
], (...arg)=> console.log(...arg))
l5("hello", "world")

Теперь у нас есть удобная функция, которая может «картировать» служебную функцию для прохождения любого количества слоев циклов.

Вы можете играть в них онлайн, используя https://repl.it/languages/javascript.

Спасибо за чтение и удачного кодирования :)