JavaScript с нуля — страница 13 из 30

Будучи людьми, мы постоянно взаимодействуем со словами — произносим, пишем и также прибегаем к их использованию при написании программ. Так уж вышло, что JavaScript тоже привязан к словам. Буквы и всяческие символы, составляющие наш с вами язык, имеют в JS свое официальное имя — строки. Строки в JavaScript — не что иное, как наборы знаков. Несмотря на то что звучит это занудно, умение обращаться к этим знакам и манипулировать ими является необходимым навыком. Этому и будет посвящен этот урок.

Поехали!

Основы

Работать со строками в коде легко. При этом нам просто нужно заключать их в одинарные или двойные кавычки. Вот некоторые примеры:

let text = "this is some text";

let moreText = 'I am in single quotes!';


console.log("this is some more text");

Помимо простого перечисления строк мы нередко будем их совмещать. Это легко делается с помощью оператора +:

let initial = "hello";

console.log(initial + " world!");


console.log("I can also " + "do this!");

Во всех этих примерах мы видим строку. Единственная причина, по которой я указываю на столь очевидный факт, в том, что когда мы видим содержимое строк так же буквально, как сейчас, эти строки правильнее называть строчные литералы. Итоговая структура при этом не меняется и по-прежнему является примитивным типом строка (как один из простых ингредиентов пиццы в предыдущей главе).

Рисунок 14.1 показывает визуальное представление строк text и moreText.

Рис. 14.1. Визуализация строк

У нас есть всего две переменные, указывающие на литеральные куски текста. Больше здесь ничего не происходит. Если вам интересно, зачем я вообще представил визуализацию столь очевидного, то стоит отметить, что визуализации существенно усложнятся, когда мы перейдем на территорию Object. В этой главе вы это отчасти увидите.

Тем не менее все это не так уж важно… пока что. Единственное, что важно помнить, — это то, что необходимо заключать строчные литералы в кавычки (") или апострофы ('), тем самым обособляя их как отдельный участок текста. Если этого не сделать, то ваш код, скорее всего, просто не запустится.

На этом основы заканчиваются. Самое же интересное начнется при использовании всего спектра функциональности JS для работы со строками. Мы перейдем к рассмотрению этой и другой информации в ближайших разделах.

Свойства и методы строк

Когда мы работаем со строками, то реализация объекта String предполагает множество свойств, обычно упрощающих работу с текстом. В последующих разделах вместо скучного изучения каждого из этих свойств я сфокусируюсь на наиболее важных, которые будут актуальны в контексте ваших задач.

Обращение к отдельным символам

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

let vowels = "aeiou";

console.log(vowels[2]);

В этом примере мы увидим знак i, так как именно этот элемент находится под индексом 2. Для наглядного представления происходящего рассмотрите рис. 14.2.

Рис. 14.2. Гласные отображены в виде индексов

Когда дело касается индекса, стоит помнить, что его позиция в JavaScript начинается с 0. Именно поэтому позиция нашего индекса 2, но порядковый номер действительной позиции элемента — 3. Вы к этому привыкнете в процессе работы с JavaScript и прочими языками, в чьих названиях не содержатся слова Visual и Basic, что подразумевало бы начало отсчета индексов с 1.

Переходим далее. Мы можем обращаться ко всем знакам строки с помощью цикла, перебирающего их индексы. Началом цикла будет 0, а завершение будет определяться длиной самой строки. Длина (то есть количество знаков) возвращается свойством length.

Рассмотрим это на примере из предыдущего раздела:

let vowels = "aeiou";


for (let i = 0; i < vowels.length; i++) {

console.log(vowels[i]);

}

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

Также существует альтернатива массиво-скобочной нотации, известная как метод charAt. Он возвращает знак согласно определенному индексу:

let vowels = "aeiou";

console.log(vowels.charAt(2));

В итоге мы получаем то же, что и в случае с описанной ранее массивоподобной нотацией. Я бы рекомендовал использовать этот метод, только если вы работаете для устаревших версий браузеров вроде Internet Explorer 7.

Погодите, что?!

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

Совмещение (конкатенация) строк

Для совмещения двух строк мы можем просто использовать операторы + или +=, складывая их как обычный набор чисел:

let stringA = "I am a simple string.";

let stringB = "I am a simple string, too!";


console.log(stringA + " " + stringB);

Обратите внимание, что в третьей строке мы складываем stringA со stringB. Между ними мы определяем пустое пространство (" "), чтобы обеспечить разделяющий их пробел. Вы можете смешивать и сопоставлять строчные литералы со строчными примитивами и строчными объектами, получая при этом все тот же совмещенный текст.

К примеру, вот рабочий вариант:

let textA = "Please";

let textB = new String("stop!");

let combined = textA + " make it " + textB;


console.log(combined);

Несмотря на все это смешение, тип переменной combined будет простым строчным примитивом.

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

let foo = "I really";

let blah = "why anybody would";

let blarg = "do this";


let result = foo.concat(" don't know", " ", blah, " ", blarg);


console.log(result);

В большинстве случаев для этой цели можете просто использовать подход с + и +=. Он быстрее, чем метод concat. А если нет разницы, то почему бы не повысить скорость кода?

Получение подстрок из строк

Иногда мы заинтересованы в определенном отрезке знаков отдельной части строки. Для удовлетворения такого интереса служат два метода — slice и substr. Предположим, у нас есть следующая строка:

let theBigString = "Pulp Fiction is an awesome movie!";

Давайте с ней немного поработаем.

Метод slice

Метод slice позволяет нам определять начальную и конечную позиции интересующей части строки, которую мы хотим извлечь:

let theBigString = "Pulp Fiction is an awesome movie!";

console.log(theBigString.slice(5, 12));

В этом примере мы извлекаем знаки между индексами 5 и 12. В итоге будет возвращено слово Fiction.

Значения начальной и конечной позиций не обязательно должны быть положительными. Если вы определите отрицательное значение конечной точки, то она будет вычислена обратным отсчетом от конца строки:

let theBigString = "Pulp Fiction is an awesome movie!";

console.log(theBigString.slice(0, -6));

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

let theBigString = "Pulp Fiction is an awesome movie!";

console.log(theBigString.slice(-14, -7));

Мы только что рассмотрели три варианта использования метода slice. Я всегда использовал только первый способ с положительными значениями начала и конца нужного отрезка, и вы, вероятно, последуете тем же путем.

Метод substr

Следующий подход для разделения строк — метод substr. Он также работает с двумя аргументами:

let newString = substr(start, length);

Первый из них является числом, определяющим стартовую позицию, а второй представляет число, задающее длину итоговой подстроки. Станет понятнее, если взглянуть на следующие примеры:

let theBigString = "Pulp Fiction is an awesome movie!";

console.log(theBigString.substr(0, 4)); // Pulp

Наша подстрока начинается с нулевой позиции и отсчитывает четыре знака вперед. Поэтому возвращается Pulp. Если мы захотим извлечь слово Fiction, то код будет выглядеть так:

let theBigString = "Pulp Fiction is an awesome movie!";

console.log(theBigString.substr(5, 7)); // Fiction

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

let theBigString = "Pulp Fiction is an awesome movie!";

console.log(theBigString.substr(5)); // Fiction is an awesome movie!

Есть еще несколько вариаций передачи значений в метод substr, но эти являются основными.

Разделение строки с помощью split

То, что вы можете объединить, можно и разделить на части. Я уверен, что это изречение одного из мудрецов. Еще одним способом разделения строк является метод split. Вызов этого метода для строки возвращает массив подстрок. Точки же разделения изначальной строки на подстроки мы определяем знаком или регулярным выражением (RegExp).

Давайте взглянем на простой пример:

let inspirationalQuote = "That which you can concatenate, you can

also split apart.";

let splitWords = inspirationalQuote.split(" ");


console.log(splitWords.length); // 10

Здесь мы разделяем текст inspirationalQuote в местах пробелов. При каждой встрече со знаком пробела оставшаяся позади часть массива удаляется и становится элементом возвращаемого массива.

Вот другой пример:

let days = "Monday,Tuesday,Wednesday,Thursday,Friday, Saturday,Sunday";

let splitWords = days.split(",");


console.log(splitWords[6]); // Sunday

У нас есть переменная days, содержащая строку дней, разделенных запятыми. Если мы хотим отделить каждый день, то можем использовать метод split с запятой в качестве разделителя. Конечным результатом будет массив из семи элементов, каждый из которых будет представлять день недели из оригинальной строки.

Вас удивит, как часто вы будете использовать метод split для разрыва последовательности знаков, которая может быть как простым предложением, так и сложными данными, возвращаемыми веб-службой.

Поиск по строке

Если нам вдруг понадобится найти знак(и) в строке, мы можем использовать методы indexOf, lastIndexOf и match. Сперва рассмотрим indexOf.

Этот метод получает искомый нами знак(и) в качестве аргумента. Если он его (их) находит, то возвращает позицию индекса строки, где происходит первое включение. Если совпадений не обнаруживается, indexOf возвращает -1. Посмотрим на пример:

let question = "I wonder what the pigs did to make these birds so

angry?";

console.log(question.indexOf("pigs")); // 18

Мы пытаемся выяснить, есть ли pigs (свиньи) в нашей строке. Так как искомый элемент существует, метод indexOf сообщает нам, что первое включение этого слова встречается в 18-м индексе. Если же мы ищем что-либо несуществующее вроде буквы z в следующем примере, возвращается значение -1:

let question = "I wonder what the pigs did to make these birds so

angry?";

console.log(question.indexOf("z")); // -1

Метод lastIndexOf очень похож на indexOf. Как можно догадаться по его имени, он возвращает индекс последнего включения искомого элемента:

let question = "How much wood could a woodchuck chuck if

a woodchuck could chuck wood?";

console.log(question.lastIndexOf("wood")); // 65

Вы можете определить еще один аргумент для описанных методов indexOf и lastIndexOf. Помимо указания искомых знаков вы можете также определить индекс строки, с которого нужно начать поиск:

let question = "How much wood could a woodchuck chuck if

a woodchuck could chuck wood?";

console.log(question.indexOf("wood", 30)); // 43

Последнее, что стоит упомянуть об indexOf и lastIndexOf, — это то, что вы можете сопоставлять любой экземпляр знаков, существующих в строке. При этом не важно, делаете вы это для целых слов или того, что ищете в виде более крупного набора знаков. Обязательно это учитывайте.

Прежде чем подвести итог, давайте рассмотрим метод match. В его случае у вас уже меньше контроля. Этот метод в качестве аргумента получает regexp:

let phrase = "There are 3 little pigs.";

let regexp = /[0–9]/;


let numbers = phrase.match(regexp);


console.log(numbers[0]); // 3

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

Строки в нижнем и верхнем регистрах

Под конец давайте рассмотрим то, что не потребует сложных объяснений. Для изменения регистра строки мы можем использовать методы с соответствующими именами, а именно toUpperCase для подъема в верхний регистр и toLowerCase для приведения в нижний. Взгляните на пример:

let phrase = "My name is Bond. James Bond.";


console.log(phrase.toUpperCase()); // MY NAME IS BOND. JAMES BOND.

console.log(phrase.toLowerCase()); // my name is bond. james bond.

Я же говорил, что это очень легко!

КОРОТКО О ГЛАВНОМ

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

Некоторые дополнительные ресурсы и примеры:

• Devowelizer (функция, исключающая гласные буквы): http://bit.ly/kirupaDeVowelize

• Капитализация первой буквы строки: http://bit.ly/kirupaCapLetter

• 10 способов развернуть строку: http://bit.ly/kirupaWaysToReverseString

Если у вас есть какие-либо вопросы, касающиеся строк… жизни или JavaScript в целом, обращайтесь за ответами на форум https://forum.kirupa.com.

Глава 15. Когда примитивы ведут себя как объекты