Какие из этих пяти вариантов — строки?
'Hello'
'Goodbye'
'G'
' '
''
Кавычки
Какие из этих пяти вариантов — строки? С первыми двумя все понятно: это точно строки, мы уже работали с подобными конструкциями. А что насчет остальных?
Любой одиночный символ в кавычках — это строка. Пустая строка '' — это тоже строка. То есть строкой мы считаем все, что находится внутри кавычек, даже если это пробел, один символ или вообще отсутствие символов.
Ранее в уроках мы записывали строки в одинарных кавычках, но это не единственный способ. Можно использовать и двойные:
// Стандарт кодирования рекомендует использовать по возможности одинарные
console.log("Dracarys!")
Представьте, что вы хотите напечатать строчку Dragon's mother. Апостроф перед буквой s — это такой же символ, как одинарная кавычка. Попробуем:
console.log('Dragon's mother')
// Uncaught SyntaxError: missing ) after argument list
Такая программа не будет работать. С точки зрения JavaScript, строка началась с одинарной кавычки, а потом закончилась после буквы n. Дальше были символы s mother без кавычек — значит, это не строка. А потом была одна открывающая строку кавычка, которая так и не закрылась: '). Этот код синтаксически некорректен (это видно даже по тому, как подсвечен код).
Здесь нам помогут двойные кавычки. Такой вариант программы отработает корректно:
console.log("Dragon's mother")
Теперь интерпретатор знает, что строка началась с двойной кавычки — значит, и закончиться должна на двойной кавычке. А одинарная кавычка внутри стала частью строки.
Верно и обратное. Если внутри строки мы хотим использовать двойные кавычки, то саму строку надо делать в одинарных. Причем количество кавычек внутри самой строки не важно.
А что, если мы хотим создать такую строку:
Dragon's mother said "No"
В ней есть и одинарные и двойные кавычки. Как быть в этой ситуации? Нужно каким-то образом сказать интерпретатору считать каждую кавычку частью строки, а не началом или концом строки.
Для этого экранируют специальные символы. В нашем случае тот символ, который является признаком конца и начала строки, это либо одинарная кавычка, либо двойная, в зависимости от ситуации. Для экранирования используется обратный слеш \.
// Экранируется только ", так как в этой ситуации
// двойные кавычки имеют специальное значение
console.log("Dragon's mother said \"No\"")
// => Dragon's mother said "No"
Посмотрите внимательно: нам нужно было добавить \ для двойных кавычек, но не для одинарной (апостроф), потому что сама строка создана с двойными кавычками. Если бы строка создавалась с одинарными кавычками, то символ экранирования нужен был бы перед апострофом, но не перед двойными кавычками:
// Обратный слеш `\` не выводится, если после него идет обычный символ,
// а не специальный
console.log("Death is \so terribly final, while life is full of possibilities")
// => Death is so terribly final, while life is full of possibilities
А что, если нужно вывести сам обратный слеш? Точно так же, как и любой другой специальный символ, его надо экранировать самим собой.
console.log("\\")
// => \
Вопрос на самопроверку, что выведет этот код?
console.log("\\ \\ \\\\ \\\ \'\"")
Экранирующие последовательности
Мы хотим показать диалог Матери Драконов со своим ребенком:
- Are you hungry?
- Aaaarrrgh!
Если вывести на экран строку с таким текстом:
console.log('- Are you hungry?- Aaaarrrgh!')
то получится так:
- Are you hungry?- Aaaarrrgh!
Не то, что мы хотели. Строки расположены друг за другом, а не одна ниже другой. Нам нужно как-то сказать интерпретатору «нажать на энтер» — сделать перевод строки после вопросительного знака. Это можно сделать, используя символ перевода строки: \n.
console.log('- Are you hungry?\n- Aaaarrrgh!')
Результат:
- Are you hungry?
- Aaaarrrgh!
\n — это специальный символ. В литературе его часто обозначают как LF (Line Feed). Возможно вы сейчас подумали, что это опечатка, ведь здесь мы видим два символа \ и n, но это не так. С точки зрения компьютера — это один невидимый символ перевода строки. Доказательство:
// Мы это не изучали, но вы должны знать правду
// Ниже код, который возвращает длину строки
'a'.length // 1
'\n'.length // 1 !!!
'\n\n'.length // 2 !!!
Почему так сделано? \n — всего лишь способ записать символ перевода строки, но сам перевод строки по своему смыслу – это один символ, правда, невидимый. Именно поэтому и возникла такая задача. Нужно было как-то представить его на клавиатуре. А поскольку количество знаков на клавиатуре ограничено и отдано под самые важные, то все специальные символы реализуются в виде таких обозначений.
Символ перевода строки не является чем-то специфичным для программирования. Все, кто хоть раз печатал на компьютере, использовал перевод строки, нажимая на Enter. Во многих редакторах есть опция, позволяющая включить отображение невидимых символов — с ее помощью можно понять, где они находятся (хотя это всего лишь схематичное отображение, у этих символов нет графического представления, они невидимые):
- Привет!¶
- О, привет!¶
- Как дела?
Устройство, которое выводит соответствующий текст, учитывает этот символ. Например, принтер при встрече с LF протаскивает бумагу вверх на одну строку, а текстовый редактор переносит весь последующий текст ниже, также на одну строку.
\n — это пример экранирующей последовательности (escape sequence). Их еще называют управляющими конструкциями. Хотя таких символов не один десяток, в программировании часто встречаются всего несколько. Кроме перевода строки, к таким символам относятся табуляция (разрыв, получаемый при нажатии на кнопку Tab) и возврат каретки (только в Windows). Нам, программистам, часто нужно использовать перевод строки \n для правильного форматирования текста.
console.log('Gregor Clegane\nDunsen\nPolliver\nChiswyck')
На экран выведется:
Gregor Clegane
Dunsen
Polliver
Chiswyck
Обратите внимание на следующие моменты:
Не имеет значения, что стоит перед или после
\n: символ или пустая строка. Перевод будет обнаружен и выполнен в любом случае.Помните, что строка может содержать один символ или вообще ноль символов. А еще строка может содержать только
\n. Проанализируйте следующий пример:
console.log('\n')
console.log('Dunsen')
// =>
// =>
// => Dunsen
Здесь мы сначала выводим строку «перевод строки», а потом делаем вывод обыкновенной строки.
Почему перед строкой Dunsen появилось две пустые строки, а не одна? Дело в том, что console.log() при выводе значения автоматически добавляет в конец символ перевода строки. Таким образом, один перевод строки мы указали явно, передав этот символ экранирующей последовательности аргументом в функцию, а второй перевод строки добавлен самой функцией автоматически.
Еще пример кода:
console.log('Polliver')
console.log('Gregor Clegane')
console.log()
console.log('Chiswyck')
console.log('\n')
console.log('Dunsen')
// => Polliver
// => Gregor Clegane
// =>
// => Chiswyck
// =>
// =>
// => Dunsen
Сейчас у вас достаточно знаний, чтобы самостоятельно разобраться и понять, почему вывод сформировался именно таким образом.
- Если нам понадобится вывести
\nименно как текст (два отдельных печатных символа), то можно воспользоваться уже известным нам способом экранирования, добавив еще один\в начале. То есть последовательность\\nотобразится как символы\иn, идущие друг за другом.
console.log('Joffrey loves using \\n')
// => Joffrey loves using \n
Небольшое, но важное замечание про Windows. В Windows для перевода строк по умолчанию используется \r\n. Такая комбинация хорошо работает только в Windows, но создает проблемы при переносе в другие системы (например, когда в команде разработчиков есть пользователи как Windows, так и Linux). Дело в том, что последовательность \r\n имеет разную трактовку в зависимости от выбранной кодировки (рассматривается позже). По этой причине, в среде разработчиков принято всегда использовать \n без \r, так как LF всегда трактуется одинаково и отлично работает в любой системе. Не забудьте настроить ваш редактор на использование \n.
Конкатенация
В веб-разработке программы постоянно оперируют строками. Все, что мы видим на сайтах, так или иначе представлено в виде текста. Этот текст чаще всего динамический, то есть полученный из разных частей, которые соединяются вместе. Операция соединения строк в программировании называется конкатенацией.
// Оператор такой же, как и при сложении чисел
// но здесь он имеет другой смысл (семантику)
console.log('Dragon' + 'stone')
// => Dragonstone
Склеивание строк всегда происходит в том же порядке, в котором записаны операнды. Левый операнд становится левой частью строки, а правый — правой.
Вот еще несколько примеров:
console.log('Kings' + 'wood') // => Kingswood
// Обратный порядок слов
console.log('road' + 'Kings') // => roadKings
// Конкатенировать можно абсолютно любые строки
console.log("King's" + 'Landing') // => King'sLanding
Как видите, строки можно склеивать, даже если они записаны с разными кавычками.
В последнем примере название города получилось с ошибкой: King's Landing нужно писать через пробел. Но в наших начальных строках не было пробелов, а пробелы в самом коде слева и справа от символа + не имеют значения, потому что они не являются частью строк.
Выхода из этой ситуации два:
// Оба способа равнозначны
// Ставим пробел в левой части
console.log("King's " + 'Landing') // => King's Landing
// Ставим пробел в правой части
console.log("King's" + ' Landing') // => King's Landing
Пробел — такой же символ, как и другие. Чем больше пробелов, тем шире отступы:
console.log("King's " + ' Landing') // => King's Landing
console.log("King's " + ' Landing') // => King's Landing