Как использовать рекурсию, чтобы превратить объект в строку?

РЕДАКТИРОВАТЬ

Мне JSON.stringify здесь не решение, так как это намного медленнее, чем рекурсия

    JSON.stringify(fakeData)
        .replace(/,/g, ';')
        .replace(/:(?={)/g, '')
        .replace(/"/g, '')
//Result
Recursion with reduce x 816,321 ops/sec ±7.38% (80 runs sampled)
JSON.stringify x 578,221 ops/sec ±1.72% (92 runs sampled)
Fastest is Recursion with reduce

Я делаю библиотеку css-in-js, и мне нужно использовать рекурсию, чтобы превратить объект в строку следующим образом:

Вход:

const fakeData = {
  a: {
    b: 'c',
    d: 'e'
  }
}

Вывод:

a{b:c;d:e;}

Моя функция рекурсии:

const buildKeyframe = (obj) => {
    return Object.entries(obj).reduce((acc, [prop, value]) => {
        if (typeof value === 'string') {
            return `${acc}${prop}:${value};`
        }

        return `${acc}${prop}:{${buildKeyframe(value)}}`
    }, '')
}

Эта функция работает, но я думаю, что есть возможности для улучшения (например, используйте TCO, избегайте использования reduce) … Как мне написать лучшую функцию для рекурсии этой структуры данных?

1 ответ
1

Я согласен, что JSON.stringify не самый подходящий для этой проблемы не только потому, что он медленнее, но и потому, что его немного сложнее понять. И вы также правы, полагая, что reduce () – не лучший инструмент для этой работы. Использование .map () обеспечивает более естественное чтение.

const convert = obj => (
  Object.entries(obj)
    .map(([key, value]) => (
      typeof value === 'string'
        ? `${key}:${value};`
        : `${key}{${convert(value)}}`
    ))
    .join('')
)

console.log(convert({
  a: {
    b: 'c',
    d: 'e'
  },
}))

При оптимизации подумайте о сценарии использования. Хотя рекурсия хвостового вызова может быть или не быть возможной, это сделает код намного более трудным для чтения, и это действительно не поможет. Основным преимуществом рекурсии хвостового вызова является экономия памяти в стеке вызовов и разрешение рекурсивной функции вызывать саму себя неограниченное количество раз, при этом в стеке используется только один кадр вызова. Не существует практического фрагмента чрезвычайно вложенного CSS, который можно было бы написать, чтобы оптимизация хвостового вызова того стоила.

В вашем вопросе скорость кажется одной из ваших основных проблем, но я немного поиграю в адвоката дьявола и спрошу, действительно ли это должно быть для этого варианта использования. Сколько CSS-in-JS вам нужно написать, прежде чем любое из этих улучшений микропроизводительности станет заметным? Десятки тысяч строк? Сотни тысяч? Я бы посоветовал сначала просто создать библиотеку, потом запустить несколько тестов и выяснить, какие ее части действительно работают медленно. Тогда беспокойтесь только об исправлении более медленных участков.

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *