Краткий обзор пары решений распространенного технического вопроса на собеседовании.

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

Напишите функцию, которая, получив строку, вернет новую строку с теми же символами в обратном порядке.

Например, мы должны ожидать, что reverse('string') вернет 'gnirts', а reverse('Hello World!') вернет '!dlroW olleH'.

Как мы должны подходить к этому? Из наших знаний о строках в JavaScript мы знаем, что, к сожалению, у нас нет никакого метода reverse(), включенного в прототип String (это было бы слишком просто!). Однако у нас есть доступ к очень похожему вспомогательному методу для массивов! Разумеется, вызов метода reverse() для массива переворачивает его на месте. Используя это в качестве отправной точки, теперь мы можем использовать вспомогательный метод строки, чтобы взять нашу строку, преобразовать ее в массив символов, для которого мы можем вызвать reverse(), чтобы изменить порядок массива, а затем преобразовать обратный массив обратно в строку, которую может вернуть наша функция.

Давайте сначала преобразуем нашу строку в массив, вызвав для нее метод split():

function reverse(str) {
  str.split('')
}

split() принимает в качестве аргумента строку, которая определяет, где произойдет разбиение. При передаче пустой строки '' наша входная строка будет разделена на каждый отдельный символ. Итак, если мы вызываем reverse('apple'), результатом str.split('') будет массив ['a', 'p', 'p', 'l', 'e']. Это хорошо — с этим можно работать! Теперь, когда у нас есть массив, мы можем вызвать reverse():

function reverse(str) {
  let reversedArray = str.split('') //assign it to a temp variable
  reversedArray.reverse()
}

На этом этапе, используя приведенный выше пример, reversedArray должен указывать на массив ['e', 'l', 'p', 'p', 'a']. Мы приближаемся. Теперь нам просто нужно взять этот массив и преобразовать его обратно в строку. К счастью для нас, мы можем использовать метод join() для выполнения действия, противоположного split() из предыдущего. Вызванная для массива функция join() создает и возвращает строку путем объединения всех элементов массива. Он принимает необязательный аргумент в виде символа-разделителя. В нашем случае мы можем вызвать его с другой пустой строкой:

function reverse(str) {
  let reversedArray = str.split('')
  reversedArray.reverse()
  reversedArray.join('')
}

Используя наш пример reverse('apple'), мы ожидаем, что это создаст строку 'elppa', именно то, что мы ищем! Теперь давайте соберем все вместе и сделаем наш код менее повторяющимся:

function reverse(str) {
  return str.split('').reverse().join('')
}

На самом деле нет необходимости хранить созданный нами массив во временной переменной, поэтому мы можем связать вызовы методов и вернуть результат. Сделанный! Однако что, если нам специально запрещено (запретили?) использовать метод массива reverse()? В конце концов, это сделало вещи очень простыми. Слишком просто, наверное..

Другое решение

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

'apple' // starting point, move 'a' to front
'paple' // move second character 'p' to front
'ppale' // move next 'p' to front
'lppae' // move 'l' to front
'elppa' // move 'e' to front, resulting in reversed 'apple'

Как мы можем написать код для этого? Чтобы перебрать всю строку, можно использовать цикл for. Теперь мы можем написать стандартный синтаксис for(var i = 0; i < str.length; i++). Однако мы современные инженеры JavaScript, поэтому давайте воспользуемся возможностью ES6 — оператором for...of:

function reverse(str) {
  let reversedString = ''
  for (char of str) {
    reversedString = char + reversedString
  }
  return reversedString
}

В этом решении мы объявляем временную переменную reversedString и инициализируем ее пустой строкой. Это строка, которую мы будем строить, последовательно добавляя каждый символ в начало строки. Вызов for (char of str) будет перебирать переданную строку, выполняя действие на каждой итерации. В нашем случае мы возьмем каждый символ и добавим его в начало reversedString. Для нашего примера с «яблоком» при первом проходе через str мы возьмем char в этой точке (первым будет «a») и добавим его к reversedString, получив 'a'. На следующем проходе (буква «p» находится рядом) reversedString будет 'pa', и так далее, пока мы полностью не перевернем входную строку.

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