Грамматика и типы
Содержание:
- [] и charAt
- Symbol.iterator
- Строка как объект
- Свойства строк
- Кавычки
- Добавление/удаление элементов
- Сравнение строк
- indexOf
- Равенство (==) и неравенство (!=)
- Поиски замена строковых значений
- Сравнение строк
- includes
- Нахождение строки в строке
- Две стадии преобразования
- Объединение
- Создание и просмотр строки
- search()
- slice()
- Доступ к символам
[] и charAt
Из любой строки
можно взять отдельный символ. Это делается с помощью оператора [], в которых
указывается индекс нужного символа. Например:
let str = 'Hello!\nI\'m Javascript.'; let ch1 = str; let ch2 = str7; console.log(ch1, ch2); console.log(typeof ch1);
Обратите
внимание, что так как в JavaScript нет символьного типа, то
возвращаемое значение – это строка, состоящая из одного символа. Ту же самую
операцию выделения символа можно выполнить и с помощью метода charAt(pos), но он менее
удобен и существует, скорее по историческим причинам для совместимости со
старыми скриптами:
Ту же самую
операцию выделения символа можно выполнить и с помощью метода charAt(pos), но он менее
удобен и существует, скорее по историческим причинам для совместимости со
старыми скриптами:
let ch1 = str.charAt(); let ch2 = str.charAt(7);
Интересной особенностью
JavaScript является
возможность перебрать строку посимвольно с помощью цикла for of, используемого
для массивов:
for(let ch of "Hello") console.log(ch);
Обратите
внимание, что строки в JavaScript изменять нельзя. Например,
нельзя выполнить такую операцию:
str = "h";
получим ошибку
исполнения. Если нужно изменить строку, то создается новая измененная строка.
Symbol.iterator
Мы легко поймём принцип устройства перебираемых объектов, создав один из них.
Например, у нас есть объект. Это не массив, но он выглядит подходящим для .
Например, объект , который представляет собой диапазон чисел:
Чтобы сделать итерируемым (и позволить работать с ним), нам нужно добавить в объект метод с именем (специальный встроенный , созданный как раз для этого).
- Когда цикл запускается, он вызывает этот метод один раз (или выдаёт ошибку, если метод не найден). Этот метод должен вернуть итератор – объект с методом .
- Дальше работает только с этим возвращённым объектом.
- Когда хочет получить следующее значение, он вызывает метод этого объекта.
- Результат вызова должен иметь вид , где означает, что итерация закончена, в противном случае содержит очередное значение.
Вот полная реализация с пояснениями:
Обратите внимание на ключевую особенность итераторов: разделение ответственности
- У самого нет метода .
- Вместо этого другой объект, так называемый «итератор», создаётся вызовом , и именно его генерирует значения.
Таким образом, итератор отделён от самого итерируемого объекта.
Технически мы можем объединить их и использовать сам как итератор, чтобы упростить код.
Например, вот так:
Теперь возвращает сам объект : у него есть необходимый метод , и он запоминает текущее состояние итерации в . Короче? Да. И иногда такой способ тоже хорош.
Недостаток такого подхода в том, что теперь мы не можем использовать этот объект в двух параллельных циклах : у них будет общее текущее состояние итерации, потому что теперь существует лишь один итератор – сам объект. Но необходимость в двух циклах , выполняемых одновременно, возникает редко, даже при наличии асинхронных операций.
Бесконечные итераторы
Можно сделать бесконечный итератор. Например, будет бесконечным при . Или мы можем создать итерируемый объект, который генерирует бесконечную последовательность псевдослучайных чисел. Это бывает полезно.
Метод не имеет ограничений, он может возвращать всё новые и новые значения, это нормально.
Конечно же, цикл с таким итерируемым объектом будет бесконечным. Но мы всегда можем прервать его, используя .
Строка как объект
По умолчанию в JavaScript строка принимает фиксированные значения, однако с помощью ключевого слова и метода строку можно превратить в объект и определить для неё какие либо свойства.
var stringObject = new string(«This string is object»); //Определение строки как объектный тип данных
stringObject.name = «newString»; //Определение свойства name со значением newString
1 |
varstringObject=newstring(«This string is object»);//Определение строки как объектный тип данных stringObject.name=»newString»;//Определение свойства name со значением newString |
Приведение строки к типу объект в большинстве случаев не представляет ценности, более того, такое преобразование способствует замедлению выполнения кода и может привести к непредвиденным последствиям.
Свойства строк
Свойство | Описание | |
---|---|---|
constructor | возвращает функцию-конструктор строки | |
var str = «Hello world!»;
|
||
length | возвращает длину (количество символов) строки | |
var str = «Hello world!»;
|
||
prototype | позволяет добавить свойства и методы к объекту (если строка — объект) | |
function student(name, surname, faculty) {
|
Кавычки
В языке JavaScript существуют различные типы кавычек. К примеру, мы можем создать строку, используя одинарные, двойные или обратные кавычки:
let single = 'single-quoted'; let double = "double-quoted"; let backticks = `backticks`;
И двойные, и одинарные кавычки работают, в принципе, одинаково. Что касается обратных, то тут есть пару отличий:
1) они позволяют вставлять в строку произвольные выражения, предварительно обёрнутые в ${…}:
function sum(a, b) { return a + b; } alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.
2) они позволяют занимать более одной строки:
let guestList = `Guests: * Bob * Petr * Maria `; alert(guestList); // список гостей из нескольких строк
Вроде бы, всё очевидно и просто, но если мы попробуем сделать то же самое, используя двойные или одинарные кавычки, то получим ошибку.
let guestList = "Guests: // Error: Unexpected token ILLEGAL * Bob";
Но вообще, и двойные, и одинарные кавычки были в JavaScript уже давно, ещё во времена, когда потребность в многострочии была не так велика. Обратные кавычки появились позже, поэтому они более гибкие в применении и лучше соответствуют современным реалиям.
Вдобавок к вышесказанному, скажем, что обратные кавычки дают возможность задавать «шаблонные функции» (они могут применяться перед первой обратной кавычкой). Тут синтаксис следующий:
func`string`
У нас автоматически вызывается функция func, получающая строку и встроенные в эту строку выражения, которые она может обработать. Если перед строкой присутствует выражение, шаблонную строку называют «теговым шаблоном». Таким образом, появляется возможность применять собственную шаблонизацию для строк, однако на деле теговые шаблоны используются нечасто.
Добавление/удаление элементов
Мы уже знаем методы, которые добавляют и удаляют элементы из начала или конца:
- – добавляет элементы в конец,
- – извлекает элемент из конца,
- – извлекает элемент из начала,
- – добавляет элементы в начало.
Есть и другие.
Как удалить элемент из массива?
Так как массивы – это объекты, то можно попробовать :
Вроде бы, элемент и был удалён, но при проверке оказывается, что массив всё ещё имеет 3 элемента .
Это нормально, потому что всё, что делает – это удаляет значение с данным ключом . Это нормально для объектов, но для массивов мы обычно хотим, чтобы оставшиеся элементы сдвинулись и заняли освободившееся место. Мы ждём, что массив станет короче.
Поэтому для этого нужно использовать специальные методы.
Метод arr.splice(str) – это универсальный «швейцарский нож» для работы с массивами. Умеет всё: добавлять, удалять и заменять элементы.
Его синтаксис:
Он начинает с позиции , удаляет элементов и вставляет на их место. Возвращает массив из удалённых элементов.
Этот метод проще всего понять, рассмотрев примеры.
Начнём с удаления:
Легко, правда? Начиная с позиции , он убрал элемент.
В следующем примере мы удалим 3 элемента и заменим их двумя другими.
Здесь видно, что возвращает массив из удалённых элементов:
Метод также может вставлять элементы без удаления, для этого достаточно установить в :
Отрицательные индексы разрешены
В этом и в других методах массива допускается использование отрицательного индекса. Он позволяет начать отсчёт элементов с конца, как тут:
Метод arr.slice намного проще, чем похожий на него .
Его синтаксис:
Он возвращает новый массив, в который копирует элементы, начиная с индекса и до (не включая ). Оба индекса и могут быть отрицательными. В таком случае отсчёт будет осуществляться с конца массива.
Это похоже на строковый метод , но вместо подстрок возвращает подмассивы.
Например:
Можно вызвать и вообще без аргументов: создаёт копию массива . Это часто используют, чтобы создать копию массива для дальнейших преобразований, которые не должны менять исходный массив.
Метод arr.concat создаёт новый массив, в который копирует данные из других массивов и дополнительные значения.
Его синтаксис:
Он принимает любое количество аргументов, которые могут быть как массивами, так и простыми значениями.
В результате мы получаем новый массив, включающий в себя элементы из , а также , и так далее…
Если аргумент – массив, то все его элементы копируются. Иначе скопируется сам аргумент.
Например:
Обычно он просто копирует элементы из массивов. Другие объекты, даже если они выглядят как массивы, добавляются как есть:
…Но если объект имеет специальное свойство , то он обрабатывается как массив: вместо него добавляются его числовые свойства.
Для корректной обработки в объекте должны быть числовые свойства и :
Сравнение строк
Если оператор отношения применяется к двум строкам, то сравнение происходит побуквенно/посимвольно. То есть сравнение происходит так: каждый символ (буква) первой строки сравнивается с соответствующим символом второй строки и так, до того момента, пока символы не будут разными, и тогда какой символ больше – та строка и больше. Если же в одной из строк закончились символы, то считаем, что она меньше, а если закончились в обеих – строки равны.
Теперь разберем, как происходит сравнение каждого символа. Каждый символ переводится в числовое значение, согласно кодировке Unicode, и суть сравнения символов сводиться к сравнению двух чисел. Например, десятичные (Dec) значения символов кирилицы лежат в диапазоне от 1024 до 1280.
Пример:
Начинаем сравнивать первые символы: str1 (буква «А») и str2 (буква «а»).
В JavaScript, как и в других языках програмирования, есть метод для получения цифрового кода из символа:
Метод возвращает код символа расположенного на позиции в строке . Отсчет позиций символов в строке начинается с нуля.
Выполнить код »
Скрыть результаты
Если бы первые символы строк были равны, то дальше сравнивались бы следующие символы попарно.
В этом примере строка считается меньше, чем строка , потому что буква имеет код , а буква – . Причина в том, что коды прописных букв всегда меньше, чем строчных.
Чтобы правильно сравнить строки по алфавиту, необходимо перед сравнением преобразовать оба операнда в один регистр (например, в нижний):
Выполнить код »
Скрыть результаты
После преобразования в нижний регистр слово «апельсин» становится больше, чем слово «абрикос», потому что вторая буква имеет код , а вторая буква переменной – .
Примечание: Обычно, буква расположенная в алфавитном порядке раньше имеет меньший числовой код, чем буква (в том же регистре) расположенная в алфавитном порядке после неё.
Не менее интересная ситуация складывается при сравнении чисел, предствленных в строковой форме, например:
Выполнить код »
Скрыть результаты
В примере выше «15»
Если хотя бы один операнд изменить на число, то другой будет преобразован к числу:
Выполнить код »
Скрыть результаты
В этом примере строка «15» преобразуется в число 15, а затем производится сравнение полученных чисел.
Когда строка сравнивается с числом, она преобразуется в число и выполняется числовое сравнение операндов.
В случае, когда строку невозможно преобразовать в число, она преобразуется в . Как правило, в результате любой операции сравнения с операндом получается :
Выполнить код »
Скрыть результаты
indexOf
Как и метод , метод использует строгое сравнение, а не функцию как метод . Однако, в отличие от , он возвращает индекс элемента, а не логическое значение. Вы также можете указать, с какого индекса массива можно начать поиск.
Я считаю очень полезным методом. Это быстрый и удобный метод, позволяющий узнать, существует ли элемент в массиве, и где именно в массиве он находится. Как он показывает, существует ли элемент? Если он возвращает положительное число, мы знаем, что элемент существует, а если он возвращает значение -1, мы понимаем, что такого элемента нет.
Как видите, хотя мы могли бы получить эту же информацию с помощью методов или , здесь нам нужно писать намного меньше кода. Нам не нужно писать функцию для сравнения, поскольку она уже входит в метод .
Как и другие методы, возвращает индекс первого найденного совпадающего элемента. JavaScript позволяет использовать альтернативный метод массива, . Как вы можете догадаться, он делает то же, что и метод , но начинает с последнего индекса массива и движется назад. Также вы можете указать второй параметр, но помните, что индексы не меняются просто потому, что вы используете другой метод.
Равенство (==) и неравенство (!=)
Оба оператора принимают операнды любого типа и, если операнды равны, оператор равенства возвращает , а оператор неравенства возвращает – .
Получив операнды разных типов, эти операторы пытаются привести их к одному типу и сравнивают уже преобразованные значения.
При преобразовании типов операторы равенства и неравенства руководствуется следующими правилами:
- Если какой-либо операнд число или булево значение, то операнды преобразуются в числа, при этом преобразуется в 1, а преобразуется в 0.
- Если какой-либо операнд строка – второй преобразуются в строку.
- Если одно из значений представляет собой объект, а другое – число или строку, то объект преобразуется в элементарный тип.
При сравнении операндов также применяются свои правила:
- Если одно из значений равно , а другое – , то они равны.
- Значения и не преобразуются для сравнения ни в какие другие значения.
- Значение считается не равным никакому другому значению, включая само себя. При его наличии оператор равенства всегда возвращает , а оператор неравенства – .
- Если оба операнда являются объектами, то они сравниваются, чтобы выяснить, один ли это
объект. Если да, возвращается , иначе – .
Примеры:
Выполнить код »
Скрыть результаты
Примечание: Значения и равны друг другу и не равны ничему другому.
Поиски замена строковых значений
С помощью метода replace() можно осуществлять поиск строки и её замену новым значением. В качестве первого параметра методу следует передать значение для поиска, а вторым – значения для замены.
constoriginalString = "How are you?" // Заменяем первое вхождение строки "How" на "Where" constnewString = originalString.replace("How", "Where"); console.log(newString); Вывод Where are you?
Также можно использовать регулярные выражения. Например, метод replace() затрагивает только первое вхождение искомой строки. Но мы можем использовать флаг g (глобальный), чтобы найти все вхождения, и флаг i (независимый от регистра), чтобы игнорировать регистр.
constoriginalString = "Javascript is a programming language. I'm learning javascript." // Ищемвсевхождениястроки"javascript" изаменяемеёна"JavaScript" constnewString = originalString.replace(/javascript/gi, "JavaScript"); console.log(newString); Вывод JavaScript is a programming language. I'm learning JavaScript.
Сравнение строк
В JavaScript для сравнения строк можно использовать операторы меньше и больше:
В JavaScript строки сравниваются посимвольно в алфавитном порядке. Сначала сравниваются первые символы строк, затем вторые, третьи… И как только какой-то символ оказывается меньше, строка считается меньше, даже если в строке больше символов. Если у какой-то строки заканчиваются символы, то она считается меньше, а если символы закончились у обоих строк одновременно – они одинаковые.
Но стоит отметить, что строки имеют внутреннюю кодировку Юникод – каждому символу соответствует свой числовой код.
Есть метод для получения символа по его коду String.fromCharCode():
Выполнить код »
Скрыть результаты
А вот метод charCodeAt() наоборот возвращает числовое значение Unicode символа, индекс которого был передан методу в качестве аргумента:
Выполнить код »
Скрыть результаты
А теперь давайте выведем интервал символов Unicode с кодами от 1025 до 1105:
Выполнить код »
Скрыть результаты
Как видите, не все символы в Юникоде соответствуют их месту в алфавите. Есть некоторые исключения. Строчные буквы идут после заглавных, поэтому они всегда больше. А буква ‘ё’, имеет код, больший чем ‘я’, поэтому ‘ё’(код 1105) > ‘я’(код 1103).
Для правильного сравнения строк используйте метод str1.localeCompare(str2), который сравнивает одну строку с другой и возвращает одно из трех значений:
- Если строка str1 должна располагаться по алфавиту перед str2, возвращается -1.
- Если строка str1 равна str2, возвращается .
- Если строка str1 должна располагаться по алфавиту после str2, возвращается 1.
includes
Метод возвращает логическое значение и позволяет определить, есть ли в массиве указанный элемент. Он выдает простой ответ или . Базовый синтаксис выглядит так:
Как видите, в нашем примере у нас был только один параметр — valueToFind. Это значение, совпадение с которым нужно было найти в массиве. Дополнительный параметр fromIndex — это число, показывающее, от какого индекса нужно начинать поиск (значение по умолчанию 0, так что поиск выполняется во всем массиве). Итак, поскольку в нашем примере элемент ‘thick scales’ находится на индексе 0, следующий код выдаст значение false: потому что он выполняет поиск, начиная с индекса 1 и далее.
Теперь нужно отметить несколько важных вещей. Этот метод использует строгое сравнение. Если взять предыдущий пример, это означает, что следующий код выдаст значение false: Это связано с тем, что хотя имеет значение true, имеет значение false — разные типы не проходят строгое сравнение.
Нахождение строки в строке
Метод возвращает индекс (положение) (первого) вхождения указанного текста в строке:
var str = «Пожалуйста, найдите, где происходит ‘locate’! «;
var pos = str.indexOf(«locate»);
JavaScript считает позиции с нуля.0 — это первая позиция в строке, 1 — это вторая, 2 — это третья и т.д.
Метод возвращает индекс last (последнего) вхождения указанного текста в строку:
var str = «Пожалуйста, найдите, где происходит ‘locate’!»;
var pos = str.lastIndexOf(«locate»);
Оба метода и возвращают -1, если текст не найден.
var str = «Пожалуйста, найдите, где происходит ‘locate’!»;
var pos = str.lastIndexOf(«John»);
Оба метода принимают второй параметр в качестве начальной позиции для поиска:
var str = «Пожалуйста, найдите, где происходит ‘locate’!»;
var pos = str.indexOf(«locate», 15);
Методы выполняют поиск в обратном направлении (от конца к началу), что означает: если второй параметр равен , поиск начинается с позиции 15 и выполняется до начала строка.
Две стадии преобразования
Итак, объект преобразован в примитив при помощи или .
Но на этом преобразования не обязательно заканчиваются. Вполне возможно, что в процессе вычислений этот примитив будет преобразован во что-то другое.
Например, рассмотрим применение к объекту операции :
Объект был сначала преобразован в примитив, используя численное преобразование, получилось .
Далее, так как значения всё ещё разных типов, применяются правила преобразования примитивов, результат: .
То же самое – при сложении с объектом при помощи :
Или вот, для разности объектов:
Исключение:
Объект по историческим причинам является исключением.
Бинарный оператор плюс обычно использует численное преобразование и метод . Как мы уже знаем, если подходящего нет (а его нет у большинства объектов), то используется , так что в итоге преобразование происходит к строке. Но если есть , то используется . Выше в примере как раз это демонстрируют.
У объектов есть и – возвращает количество миллисекунд, и – возвращает строку с датой.
…Но оператор для использует именно (хотя должен бы ).
Это и есть исключение:
Других подобных исключений нет.
Как испугать Java-разработчика
В языке Java (это не JavaScript, другой язык, здесь приведён для примера) логические значения можно создавать, используя синтаксис , например .
В JavaScript тоже есть подобная возможность, которая возвращает «объектную обёртку» для логического значения.
Эта возможность давно существует лишь для совместимости, она и не используется на практике, поскольку приводит к странным результатам. Некоторые из них могут сильно удивить человека, не привыкшего к JavaScript, например:
Почему запустился ? Ведь в находится … Проверим:
Дело в том, что – это не примитивное значение, а объект. Поэтому в логическом контексте он преобразуется к , в результате работает первый пример.
А второй пример вызывает , который преобразует объект к строке, и он становится .
В JavaScript вызовы не используются, а используются простые вызовы соответствующих функций, они преобразуют значение в примитив нужного типа, например .
Объединение
Рассмотрим основные аспекты, связанные с объединением строк и строковых переменных.
Стандартный способ:
let s1 = ‘Hello’;
let s2 = ‘world’;
let s3 = s1 + s2 + ‘!’;
console.log(s3); // Hello world!
Вместо одинарных кавычек можно использовать двойные. Кроме этого, кавычки внутри строки можно экранировать обратным слешем.
let s1 = «It’s string»;
let s2 = ‘It\’s string’;
Применяется в JavaScript и ещё один тип кавычек — обратные. Их применяют для использования переменных внутри строк.
let s1 = ‘Hello’;
let s2 = ‘world’;
let s3 = `${s1} ${s2}!`;
console.log(s3); // Hello world!
Ещё один способ объединения, использовать функцию «concat».
let s1 = ‘Hello’;
let s2 = ‘world’;
let s3 = s1.concat(‘ ‘, s2, ‘!’);
console.log(s3); // Hello world!
Здесь в переменную «s3», будет присваиваться значение переменной «s1», объедененное с пробелом, «s2» и восклицательным знаком
Важно, значение «s1» не изменится
Создание и просмотр строки
В JavaScript существует три способа создания троки: их можно писать в одинарных кавычках (‘), в двойных (“) или в обратных кавычках (`). Хотя иногда в сценариях встречаются строки всех трех типов, в рамках одной строки нужно использовать только один тип кавычек.
Строки в одинарных и двойных кавычках – это, по сути, одно и то же. Не существует никаких соглашений касательно использования того или иного типа кавычек, но обычно в сценариях программы рекомендуется последовательно использовать какой-нибудь один тип.
Третий и новейший способ создания строки называется шаблонным литералом. Шаблонные литералы пишутся в обратных кавычках (также этот символ называется тупым ударением) и работают так же, как обычные строки с несколькими дополнительными функциями, которые мы рассмотрим в этой статье.
Простейший способ просмотреть вывод строки – ввести ее в консоль с помощью console.log().
Другим простым способом запросить значение строки является всплывающее окно в браузере, которое можно вызвать с помощью alert():
Эта строка откроет в браузере окно уведомления с таким текстом:
Метод alert() используется реже, поскольку оповещения нужно постоянно закрывать.
search()
Отдаёт расположение первого совпадения строки в заданной строке.
Этот метод отдаёт индекс начала упоминания или , если такого не было найдено.
Вы можете использовать регулярные выражения (и на самом деле, даже если вы передаёте строку, то внутренне оно тоже применяется как регулярное выражение).
slice()
Отдает новую строку, которая является частью строки на которой применялся метод, от позиций до .
Оригинальная строка не изменяется.
опциональна.
Если вы выставите первым параметром отрицательное число, то начальный индекс будет считаться с конца и второй параметр тоже должен быть отрицательным, всегда ведя отсчет с конца:
Доступ к символам
Продемонстрируем, как получить доступ к символам и индексам строки How are you?
"How are you?";
Используя квадратные скобки, можно получить доступ к любому символу строки.
"How are you?"; Вывод r
Мы также можем использовать метод charAt(), чтобы вернуть символ, передавая индекс в качестве параметра.
"Howareyou?".charAt(5); Вывод r
Также можно использовать indexOf(), чтобы вернуть индекс первого вхождения символа в строке.
"How are you?".indexOf("o"); Вывод 1
Несмотря на то, что символ «o» появляется в строке How are you? дважды, indexOf() вернёт позицию первого вхождения.
lastIndexOf() используется, чтобы найти последнее вхождение.
"How are you?".lastIndexOf("o"); Вывод 9
Оба метода также можно использовать для поиска нескольких символов в строке. Они вернут индекс первого символа.
"How are you?".indexOf("are"); Вывод 4
А вот метод slice() вернёт символы между двумя индексами.
"How are you?".slice(8, 11); Вывод you
Обратите внимание на то, что 11– это ?, но? не входит в результирующую строку. slice() вернёт всё, что между указанными значениями индекса
Если второй параметр опускается, slice() вернёт всё, начиная от первого параметра до конца строки.
"How are you?".slice(8); Вывод you?
Методы charAt() и slice() помогут получить строковые значения на основании индекса. А indexOf() и lastIndexOf() делают противоположное, возвращая индексы на основании переданной им строки.