Get to know MDN better
This page was translated from English by the community. Learn more and join the MDN Web Docs community.
Почему повторное введение? Потому что JavaScript известен тем, что является самым неправильно понятым языком программирования в мире. Его часто называют игрушкой, но под слоем обманчивой простоты ожидают мощные языковые возможности. В настоящее время JavaScript используется невероятным количеством высококлассных приложений, показывая, что углублённое знание этой технологии является важным навыком для любого веб или мобильного разработчика.
Было бы полезно начать с истории языка. JavaScript был создан в 1995 Бренданом Айком, инженером в компании Netscape. Первый релиз состоялся вместе с выходом браузера Netscape 2 в начале 1996 года. Сначала язык назывался LiveScript, но затем был переименован в связи с маркетинговыми целями, чтобы сыграть на популярности языка Java компании Sun Microsystem — несмотря на это языки практически не имеют ничего общего друг с другом. Так было положено начало путаницы между этими языками.
Чуть позже Microsoft выпустила очень похожий и практически совместимый язык JScript, который шёл вместе с IE3. Через пару месяцев Netscape отправил язык в Ecma International, Европейскую организацию занимающуюся стандартами, которая выпустила первую версию стандарта ECMAScript в 1997. Стандарт получил значимое обновление в ECMAScript edition 3 в 1999, и остаётся самым стабильным до сегодняшнего дня. Четвёртая версия была отклонена, из-за проблем с усложнениями в языке. Многие вещи из четвёртого издания послужили основой для стандарта ECMAScript 5 (декабрь 2009) и ECMAScript 6 (июнь 2015).
В отличие от большинства языков, JavaScript не следует концепции ввода (input) и вывода (output). Он спроектирован таким образом, чтобы запускаться как язык сценариев, встроенный в среду исполнения. Самая популярная среда исполнения это браузер, однако интерпретаторы JavaScript присутствуют и в Adobe Acrobat, Photoshop, Yahoo!'s Widget engine, и даже в серверном окружении, например node.js.
JavaScript является объектно-ориентированным языком, имеющий типы и операторы, встроенные объекты и методы. Его синтаксис происходит от языков Java и C, поэтому много конструкций из этих языков применимы и к JavaScript. Одним из ключевых отличий JavaScript является отсутствие классов, вместо этого функциональность классов осуществляется прототипами объектов (смотрите ES6 Classes) . Другое главное отличие в том, что функции это объекты, в которых содержится исполняемый код и которые могут быть переданы куда-либо, как и любой другой объект.
Начнём с основы любого языка: с типов данных. Программы на JavaScript оперируют значениями, и все эти значения принадлежат к определённому типу. Типы данных в JavaScript:
Да, ещё Undefined и Null, которые немного обособлены. И Массивы, которые являются особым видом объектов. А также Даты и Регулярные выражения, тоже являющиеся объектами. И, если быть технически точным, функции это тоже особый вид объекта. Поэтому схема типов выглядит скорее так:
Символы (новый тип из шестой редакции)
Также есть несколько встроенных типов Ошибок. Чтобы было проще, рассмотрим подробнее первую схему.
Числа в JavaScript — это "64-битные значения двойной точности формата IEEE 754", согласно спецификации. Это имеет интересные последствия. В JavaScript нет такой вещи, как целое число, поэтому с арифметикой нужно быть начеку, если вы привыкли к вычислениям в языках C или Java. Взгляните на пример:
На практике целые значения это 32-битные целые (и хранятся таким образом в некоторых браузерных реализациях), что может быть важно для побитовых операций.
Поддерживаются стандартные арифметические операторы, включая сложение, вычитание, остаток от деления и т.д. Есть ещё встроенный объект, который я забыл упомянуть, называемый Math, который содержит более продвинутые математические функции и константы:
Вы можете преобразовать строку в целое число, используя встроенную функцию parseInt(). Её необязательный второй параметр — основание системы счисления, которое следует всегда явно указывать:
Если вы не предоставите основание, то можете получить неожиданные результаты:
Это случилось потому, что функция parseInt() расценила строку как восьмеричную из-за начального 0, а шестнадцатеричную - из-за начального "0x".
Если хотите преобразовать двоичное число в десятичное целое, просто смените основание:
Вы можете аналогично парсить дробные числа, используя встроенную функцию parseFloat(), которая использует всегда основание 10 в отличие от родственной parseInt().
Также можно использовать унарный оператор + для преобразования значения в число:
Специальное значение NaN (сокращение от "Not a Number") возвращается, если строка не является числом:
NaN "заразителен": любая математическая операция над NaN возвращает NaN:
Проверить значение на NaN можно встроенной функцией isNaN():
JavaScript также имеет специальные значения Infinity (бесконечность) и -Infinity:
Проверить значение на Infinity, -Infinity и NaN можно с помощью встроенной функции isFinite():
Строки в JavaScript - это последовательности символов Unicode (в кодировке UTF-16). Для тех, кто имеет дело с интернационализацией, это должно стать хорошей новостью. Если быть более точным, то строка - это последовательность кодовых единиц, каждая из которых представлена 16-битовым числом, а каждый символ Unicode состоит из 1 или 2 кодовых единиц.
Чтобы представить единственный символ, используйте строку, содержащую только этот символ.
Чтобы выяснить длину строки (в кодовых единицах), используйте свойство length:
Это уже первый шаг для работы с объектами! Мы уже говорили, что и строки можно использовать как объекты? У них тоже есть методы:
JavaScript дополнительно различает такие типы, как null, который указывает на преднамеренное отсутствующее значение, и undefined, указывающий на неинициализированное значение — то есть, значение, которое даже не было назначено. Мы поговорим о переменных позже, но в JavaScript можно объявить переменную без присвоения ей значения. В этом случае тип переменной будет "undefined".
Ещё в JavaScript есть логический (булевый) тип данных, который может принимать два возможных значения true или false (оба являются ключевыми словами). Любое значение может быть преобразовано в логическое значение в соответствии со следующими правилами:
Преобразование значений можно осуществить явно, используя функцию Boolean():
Этот метод используется редко, так как JavaScript может автоматически преобразовывать типы в тех случаях, когда ожидается булевое значение, например в операторе if. Из-за того, что любой тип данных может быть преобразован в булевое значение, иногда говорят, что данные "истинные" или "ложные".
Для операций с логическими данными используются логические операторы: && (логическое И), || (логическое ИЛИ), ! (логическое НЕ).
Для объявления новых переменных в JavaScript используются ключевые слова let, const или var.
let позволяет объявлять переменные, которые доступны только в блоке, в котором они объявлены:
const позволяет создавать переменные, чьи значения не предполагают изменений. Переменная доступна из блока, в котором она объявлена.
var наиболее общее средство объявления переменной. Оно не имеет ограничений, которые имеют два вышеописанных способа. Это потому, что это был изначально единственный способ объявления переменной в JavaScript. Переменная, объявленная с помощью var, доступна в пределах функции, в которой она объявлена.
Пример кода с переменной, объявленной с помощью var:
Если вы объявляете переменную без присвоения ей какого-либо значения, то её тип будет определён как undefined.
Важной особенностью языка JavaScript является то, что блоки данных не имеют своей области видимости, она есть только у функций. Поэтому, если объявить переменную через var в блоке данных (например, внутри контролирующей структуры if), то она будет доступна всей функции. Следует отметить, что в новом стандарте ECMAScript Edition 6 появились инструкции let и const, позволяющие объявлять переменные с областью видимости, ограниченной пределами блока.
JavaScript поддерживает такие операторы, как +, -, *, / и %, который возвращает остаток от деления (не путать с модулем). Значения присваиваются с помощью оператора =, или с помощью составных операторов += и -=. Это сокращённая запись выражения x = x оператор y.
Так же используются операторы инкремента (++) и декремента (--). Которые имеют префиксную и постфиксную форму записи.
Оператор + так же выполняет конкатенацию (объединение) строк:
При сложении строкового и числового значений происходит автоматическое преобразование в строку. Поначалу такое может запутать:
Для приведения значения к строке просто прибавьте к нему пустую строку.
Для сравнения в JavaScript используются следующие операторы: <, >, <= и >=. Сравнивать можно не только числа, но и строки. Проверка на равенство немного сложнее. Для проверки используют двойной (==) или тройной (===) оператор присваивания. Двойной оператор == осуществляет автоматическое преобразование типов, что может приводить к интересным результатам:
Если преобразование нежелательно, то используют оператор строгого равенства:
Для проверки на неравенство используют операторы != и !==.
Отдельного внимания стоят побитовые операторы, с которыми вы можете ознакомиться в соответствующем разделе.
Управляющие структуры в JavaScript очень похожи на таковые в языках семейства C. Условные операторы выражены ключевыми словами if и else, которые можно составлять в цепочки:
В JavaScript есть три типа циклов: while, do-while и for. While используется для задания обычного цикла, а do-while целесообразно применить в том случае, если вы хотите, чтобы цикл был выполнен хотя бы один раз:
Цикл for похож на такой же в языках C и Java: он позволяет задавать данные для контроля за выполнением цикла:
JavaScript также содержит две других известных конструкции: for...of
и for...in:
Логические операторы && и || используют "короткий цикл вычисления", это значит, что вычисление каждого последующего оператора зависит от предыдущего. Например, полезно проверить существует ли объект или нет, прежде чем пытаться получить доступ к его свойствам:
Таким способом удобно задавать значения по умолчанию:
К условным операторам в JavaScript принадлежит также тернарный оператор "?" :
Оператор switch используется при необходимости множественного сравнения:
Если в конце инструкции case не добавить останавливающую инструкцию break, то выполнение перейдёт к следующей инструкции case. Как правило, такое поведение нежелательно, но если вдруг вы решили его использовать, настоятельно рекомендуем писать соответствующий комментарий для облегчения поиска ошибок:
Вариант default опциональный. Допускается использование выражений как в условии switch, так и в cases. При проверке на равенство используется оператор строгого равенства ===:
Объекты в JavaScript представляют собой коллекции пар имя-значение (ключ-значение). Они похожи на:
Именем свойства объекта в JavaScript выступает строка, а значением может быть любой тип данных JavaScript, даже другие объекты. Это позволяет создавать структуры данных любой сложности.
Существует два основных способа создать объект:
А также:
Обе эти записи делают одно и то же. Вторая запись называется литералом объекта и более удобная. Такой способ является основой формата JSON, и при написании кода лучше использовать именно его.
С помощью литерала объекта можно создавать не только пустые объекты, но и объекты с данными:
Доступ к свойствам объекта можно получить следующими способами:
Эти два метода равнозначны. Первый метод используется, если мы точно знаем к какому методу нам нужно обратиться. Второй метод принимает в качестве имени свойства строку, и позволяет вычислять имя в процессе вычислений. Следует отметить, что последний метод мешает некоторым движкам и минимизаторам оптимизировать код. Если появится необходимость назначить в качестве имён свойств объекта зарезервированные слова, то данный метод тоже может пригодиться:
Больше информации об объектах и прототипах: Object.prototype.
Для получения информации по прототипам объектов и цепям прототипов объектов смотрите Inheritance and the prototype chain.
Массивы в JavaScript всего лишь частный случай объектов. Работают они практически одинаково (если именем свойства является число, то доступ к нему можно получить только через вызов в скобках []), только у массивов есть одно удивительное свойство length (длина). Оно возвращает число, равное самому большому индексу массива + 1.
Создать массив можно по старинке:
Но гораздо удобнее использовать литерал массива:
Запомните, свойство array.length не обязательно будет показывать количество элементов в массиве. Посмотрите пример:
Запомните — длина массива это его самый большой индекс плюс один.
Если попытаться получить доступ к несуществующему элементу массива, то получите undefined:
Для перебора элементов массива используйте такой способ:
ES2015 представляет более краткий for...of способ обхода по итерируемым объектам, в т.ч. массивам:
for (const currentValue of a) { // Сделать что-нибудь с currentValue }Перебрать элементы массива также можно с помощью цикла for...in. Но, если вдруг будет изменено какое-либо свойство Array.prototype, то оно тоже будет участвовать в выборке. Не используйте данный метод.
И самый новый способ перебора свойств массива был добавлен в ECMAScript 5 — это метод forEach():
Для добавления данных в массив используйте метод push():
У массивов есть ещё множество полезных методов. С их полным списком вы можете ознакомиться по ссылке.
| a.toString() | Возвращает строковое представление массива, где все элементы разделены запятыми. |
| a.toLocaleString() | Возвращает строковое представление массива в соответствии с выбранной локалью. |
| a.concat(item1[, item2[, ...[, itemN]]]) | Возвращает новый массив с добавлением указанных элементов. |
| a.join(sep) | Преобразует массив в строку, где в качестве разделителя используется параметр sep |
| a.pop() | Удаляет последний элемент массива и возвращает его. |
| a.push(item1, ..., itemN) | Добавляет один или более элементов в конец массива. |
| a.reverse() | Меняет порядок элементов массива на обратный. |
| a.shift() | Удаляет первый элемент массива и возвращает его. |
| a.slice(start[, end]) | Возвращает новый массив. |
| a.sort([cmpfn]) | Сортирует данные в массиве. |
| a.splice(start, delcount[, item1[, ...[, itemN]]]) | Позволяет вырезать из массива его часть и добавлять на это место новые элементы. |
| a.unshift(item1[, item2[, ...[, itemN]]]) | Добавляет элементы в начало массива. |
Наряду с объектами функции также являются ключевыми компонентами языка JavaScript. Базовые функции очень просты:
В этом примере показано практически всё, что нужно знать о функциях. Функции в JavaScript могут принимать ноль или более параметров. Тело функции может содержать любые выражения и определять свои собственные переменные, которые будут для этой функции локальными. Инструкция return используется для возврата значения и остановки выполнения функции. Если инструкции return в функции нет (или есть, но не указано возвращаемое значение), то JavaScript возвратит undefined.
Можно вызвать функцию, вообще не передавая ей параметры. В таком случае будет считаться, что их значения равны undefined:
Можно передать больше аргументов, чем ожидает функция:
Это может показаться бессмысленным, но на самом деле функции могут получить доступ к "лишним" аргументам с помощью псевдомассива arguments, в нём содержатся значения всех аргументов, переданных функции. Давайте напишем функцию, которая принимает неограниченное количество аргументов:
Или создадим функцию для вычисления среднего значения:
Это довольно полезно, но при этом кажется излишне подробным. Для уменьшения количества кода взглянем на замену использования массива аргументов синтаксисом остаточных параметров. В этом случае мы можем передавать в функцию любое количество аргументов, сохраняя код минималистичным. Оператор остаточных параметров используется в списке параметров функции в формате: ...variable и включает в себя целый список аргументов, с которыми функция будет вызвана. Мы будем также использовать замену цикла for циклом for...of для получения значений, которые будет содержать наша переменная.
В JavaScript можно создавать анонимные функции:
Данная запись семантически равнозначна записи function avg(). Это даёт возможность использовать разные интересные трюки. Вот посмотрите, как можно "спрятать" локальные переменные в функции:
В JavaScript есть возможность рекурсивного вызова функции. Это может оказаться полезным при работе с иерархическими (древовидными) структурами данных (например такие, которые встречаются при работе с DOM).
Тут мы сталкиваемся с проблемой: как вызвать функцию рекурсивно, если у неё нет имени? Для этого в JavaScript есть именованные функциональные выражения IIFEs (Immediately Invoked Function Expressions). Вот пример использования именованной самовызывающейся функции:
Имя функции в примере доступно только внутри самой функции. Это улучшает оптимизацию и читаемость кода.
В классическом Объектно-Ориентированном Программировании (ООП) объекты — это коллекции данных и методов, которые этими данными оперируют. JavaScript - это язык, основанный на прототипах, и в его определении нет понятия классов, таких, как в языках C++ или Java. (Иногда это может запутать программистов, знакомых с языками, в которых есть классы.) Вместо классов JavaScript использует функции. Давайте представим объект с личными данными, содержащий поля с именем и фамилией. Есть два типа отображения имён: "Имя Фамилия" или "Фамилия, Имя". С помощью объектов и функций можно сделать следующее:
Работает, но сам код никуда не годится. С таким подходом у вас будут десятки функций, засоряющих глобальный объект. Это можно исправить, прикрепив функцию к объекту. Это просто, ведь все функции и есть объекты:
А вот кое-что новенькое: ключевое слово this. Когда this используется внутри функции, оно ссылается на текущий объект. Значение ключевого слова зависит от способа вызова функции. Если вызвать функцию с обращением к объекту через точку или квадратные скобки, то this получится равным данному объекту. В ином случае this будет ссылаться на глобальный объект. Это часто приводит к ошибкам. Например:
При вызове fullName(), this получает ссылку на глобальный объект. А так как в глобальном объекте не определены переменные first и last, то имеем два undefined.
Используя особенность ключевого слова this, можно улучшить код функции makePerson:
В примере мы использовали новое ключевое слово: new. Оно тесно связано с this. Данное ключевое слово создаёт новый пустой объект, а потом вызывает указанную функцию, а this получает ссылку на этот новый объект. Функции, которые предназначены для вызова с new называются конструкторами. Существует соглашение, согласно которому все функции-конструкторы записываются с заглавной буквы.
Мы доработали наш код в предыдущем примере, но всё равно остался один неприятный момент с самостоятельным вызовом fullName().
Каждый раз, когда с помощью конструктора создаётся новый объект, мы заново создаём и две новые функции. Гораздо удобнее создать эти функции отдельно и дать доступ к ним конструктору:
Уже лучше: мы создали функции-методы только один раз, а при новом вызове функции-конструктора просто ссылаемся на них. Можно сделать ещё лучше? Конечно:
Person.prototype это объект, доступ к которому есть у всех экземпляров класса Person. Он создаёт особую цепочку прототипов. Каждый раз, когда вы пытаетесь получить доступ к несуществующему свойству объекта Person, JavaScript проверяет, существует ли свойство в Person.prototype. В результате все, что передано в Person.prototype, становится доступным и всем экземплярам этого конструктора через this объект.
Это очень мощный инструмент. JavaScript позволяет изменять прототипы в любое время, это значит, что можно добавлять новые методы к существующим объектам во время выполнения программы:
Занимательно то, что добавлять свойства в прототип можно и для встроенных объектов JavaScript. Давайте добавим новый метод reversed классу String, этот метод будет возвращать строку задом наперёд:
Данный метод будет работать даже на литералах строки!
Как уже упоминалось, prototype формирует часть цепочки. Конечным объектом этой цепочки прототипов является Object.prototype, методы которого включают и toString() — тот метод, который вызывается тогда, когда надо получить строковое отображение объекта. Вот что можно сделать с нашими объектами Person:
Помните, мы вызывали avg.apply() с первым аргументом равным null? Теперь мы можем сделать так: первым аргументом, переданным методу apply() будет объект, который примет значение this. Вот к примеру упрощённая реализация new:
Это не точная копия new, так как она не устанавливает цепочку прототипов (это сложно ). Метод apply() применяется не очень часто, но знать его важно. В примере выше, синтаксис ...args (включая многоточие) называется остаточными параметрами, потому что они включают в себя все оставшиеся аргументы.
Вызов
практически полностью эквивалентен этому:
В JavaScript метод apply() имеет похожий метод call(), который тоже позволяет устанавливать this, но принимает список, а не массив аргументов.
Объявлять новые функции можно и внутри других функций. Мы использовали этот приём чуть выше, создавая функцию makePerson(). Главная особенность вложенных функций в том, что они получают доступ к переменным, объявленным в их функции-родителе:
Это очень полезное свойство, которое делает сопровождение кода более удобным. Если ваша функция в своей работе использует другие функции, которые больше нигде не используются, то можно просто вложить вспомогательные функции в основную. Это сократит количество функций в глобальном объекте, что довольно неплохо.
Ещё это отличный способ сократить количество глобальных переменных. Так при написании кода у нас часто будет возникать искушение понасоздавать глобальных переменных, которые будут доступны разным функциям. Всё это усложняет код, делает его менее читаемым. Вложенные функции имеют доступ к переменным своей функции-родителя, и мы можем использовать это для группировки множества функций вместе (естественно в разумных пределах), что позволит держать наш глобальный объект в чистоте и порядке.
Мы подошли к одному из самых мощных и непонятных инструментов JavaScript. Давайте разберёмся.
Функция makeAdder создаёт новую функцию, которая прибавляет полученное значение к значению, которые было получено при создании функции.
Такой же фокус мы наблюдали в предыдущем примере, когда внутренние функции получали доступ к переменным той функции, в которой были объявлены. Только в нашем примере основная функция возвращает вложенную. Поначалу может показаться, что локальные переменные при этом перестанут существовать. Но они продолжают существовать — иначе код попросту не сработал бы. Вдобавок ко всему у нас есть две разные "копии" функции makeAdder, присвоенные разным переменным (одна копия, в которой а - это 5, а во второй а - это 20). Вот что имеем в результате вызова:
И вот что произошло: когда JavaScript выполняет функцию, создаётся объект 'scope', который содержит в себе все локальные переменные, объявленные внутри этой функции. Он инициализируется любым значением, переданным функции в качестве параметра. 'Scope' подобен глобальному объекту, который содержит все глобальные переменные и функции, кроме нескольких важных отличий: при каждом вызове функции создаётся новый объект 'scope' и, в отличие от глобального, к объекту 'scope' нельзя получить прямой доступ из вашего кода. И нет способа пройтись по свойствам данного объекта.
Так что при вызове функции makeAdder создаётся новый объект 'scope' с единственным свойством: a, которому присваивается значение, переданное функции в качестве аргумента. Потом makeAdder возвращает новую анонимную функцию. В любом другом случае 'сборщик мусора' удалил бы объект scope, но возвращаемая функция ссылается на этот объект. В итоге объект scope не удаляется до тех пор, пока существует хотя бы одна ссылка на него.
Все объекты scope соединяются в цепочку областей видимости, которая похожа на цепочку прототипов в объектной системе JavaScript.
Замыкание это связка из функции и объекта scope, созданного при её вызове. Подробнее о замыканиях здесь.
This page was last modified on 10 апр. 2026 г. by MDN contributors.
Your blueprint for a better internet.
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998–2026 by individual mozilla.org contributors. Content available under a Creative Commons license.