Работа с объектами и прототипами
Если ООП для вас новое или вы учите JavaScript с нуля, сначала пройдите материалы без привязки к синтаксису: парадигмы и уровни абстракции, затем ООП — о разделе — зачем объекты, введение, абстракция, инкапсуляция, наследование, полиморфизм.
Ниже — объекты, прототипы и классы ES6 в JavaScript.
Теория и модель JavaScript
| Понятие ООП | Как выражено в JavaScript |
|---|---|
| Объект | литералы {}, ссылочная семантика |
| Класс | class ES6 — синтаксический сахар над прототипами |
| Наследование | цепочка [[Prototype]], extends |
| Инкапсуляция | поля класса #private, замыкания, модули ES |
| Полиморфизм | duck typing; один интерфейс — разные объекты |
| Сообщения | вызов метода; близко к модели Smalltalk |
Определения — раздел 4-08-oop.
Работа с объектами
Создание литерала, доступ через точечную и скобочную нотацию, изменение полей, деструктуризация и методы с this — в главе Типы данных — объект. Ниже — прототипы, классы ES6 и ООП в JavaScript.
Синтаксис class, constructor и методы экземпляра удобнее всего отработать на виджете с DOM: промо-карусель с init() и автопрокруткой — в главе Виджеты интерфейса на ванильном JavaScript (разметка — в CSS, промо-карусель).
Интерактивная схема — класс и объект (псевдокод; в JS классы ES6 — сахар над прототипами). Полный разбор принципов: ООП в разделе "Код и разработка".
КЛАСС Кот
поля: имя, возраст
метод мяукнуть()
КОНЕЦ
объект barsik := новый Кот(имя="Барсик", возраст=3)
barsik.мяукнуть()
Разбор:
- Это псевдокод, который иллюстрирует базовую модель ООП: сначала описывается шаблон сущности (класс), затем создаётся конкретный экземпляр (объект).
- Блок
поля — имя, возрастзадаёт состояние объекта — данные, которые хранятся у каждого экземпляра отдельно. - Строка
метод мяукнуть()показывает поведение объекта: методы связывают действия с конкретным типом сущности. новый Кот(...)демонстрирует инстанцирование, где в объект передаются начальные значения полей.- Вызов
barsik.мяукнуть()показывает точечную нотацию доступа к методам экземпляра. - Такая схема помогает понять, как от абстракции перейти к реальному объекту в коде JavaScript.
Play ITЗагрузка интерактивного демо…
JavaScript — прототипно-ориентированный язык. Классы (ES6+) — это синтаксический сахар над прототипами. Всё, включая функции и массивы, — объекты.
Главное отличие от Java/C++/C#: нет классов в классическом понимании. Наследование — через цепочку прототипов.
Современный синтаксис (ES6+ class):
Код ITЗагрузка примера кода…
Разбор:
class Warriorобъявляет класс с полями, методами, геттерами и статическими членами, то есть полный современный ES6+ синтаксис.static countиstatic getCount()относятся к самому классу, а не к экземплярам; это удобно для общей статистики.constructor(name, level = 1)выполняется приnewи инициализирует состояние черезthis.- Геттер
get damage()вычисляет значение как свойство, поэтому вызывается без скобок и выглядит как обычное поле. class Knight extends Warriorвключает наследование, аsuper(...)иsuper.attack(...)дают доступ к логике родителя.- Переопределение
attackдемонстрирует полиморфизм: дочерний класс меняет поведение, сохраняя общий контракт метода. - Финальный блок использования показывает жизненный цикл: создание объектов, вызов методов и чтение геттера.
Прототипная сущность:
Код ITЗагрузка примера кода…
Разбор:
- Пример показывает "классическую" прототипную модель до
class: функции-конструкторы и ручную работу сprototype. WarriorOldзадаёт поля черезthis, а методattackдобавляется вWarriorOld.prototype, чтобы не копировать функцию в каждый объект.- В
KnightOldвызовWarriorOld.call(this, name)имитирует вызов родительского конструктора и переносит базовую инициализацию. KnightOld.prototype = Object.create(WarriorOld.prototype)строит корректную цепочку прототипов для наследования методов.- Восстановление
constructorважно для корректной рефлексии и диагностики типа объекта. - Вызов
w.attack()подтверждает, что метод найден по прототипной цепочке, хотя в самом объектеwон явно не объявлен.
ES6 class делает ТОЧНО ТАК ЖЕ, просто красивее.
Прототипная цепочка (как работает "наследование"):
const arr = [1, 2, 3];
console.log(arr.__proto__ === Array.prototype); // true
console.log(Array.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
// Поиск свойства: arr -> Array.prototype -> Object.prototype -> null
arr.push(4); // нашли в Array.prototype
arr.toString(); // нашли в Object.prototype (переопределён в Array)
Получается, классов тут нет. Есть объекты, которые ссылаются на другие объекты (прототипы).
В ES2022 добавили приватные поля:
Код ITЗагрузка примера кода…
Но!
Главное отличие - объекты без классов.
Код ITЗагрузка примера кода…
Это замыкания + фабрики вместо классов. Без this, без new, с реальной приватностью.
JavaScript не классический ООП-язык. Он прототипный. И классы ES6 — это не то же самое, что классы в Java.
Философия JS: объекты напрямую наследуют от других объектов. Классы — просто удобная обёртка.
this
В JavaScript, для получения данных (свойств, методов) текущего объекта, используется ключевое слово this.
Когда говорит Петя, то "я" в его речи говорит именно о нём. Когда говорит Маша, то "я" в её речи - о ней.
В программировании так же - если сейчас выполняется код внутри объекта, то this, подобно "я", будет ссылкой на объект, который вызывает текущий код в данный момент.
В глобальной области — this это объект window (браузер):
console.log(this); // Window { ... }
function showThis() {
console.log(this); // Window (в нестрогом режиме)
}
showThis(); // Window
А вот внутри метода объекта this будет означать сам объект:
const user = {
name: "Alice",
greet: function() {
console.log(this.name); // this = user
console.log(this); // { name: "Alice", greet: f }
}
};
user.greet(); // "Alice"
В конструкторе/классе this будет означать новый создаваемый объект:
Код ITЗагрузка примера кода…
А в стрелочных функциях this берётся из родительской области:
Код ITЗагрузка примера кода…
thisопределяется в момент ВЫЗОВА функции, а не в момент её создания. А стрелочные функции — исключение, они берутthisиз места своего создания.
Пример класса в JS
Код ITЗагрузка примера кода…
Ключевое слово class определяет новый класс. Внутри фигурных скобок размещаются свойства и методы класса.
Метод constructor вызывается автоматически при создании нового объекта с помощью оператора new. В конструкторе инициализируются начальные значения свойств объекта.
Каждое свойство объекта хранит конкретное значение. Свойства определяются через ключевое слово this, которое ссылается на текущий экземпляр класса.
Метод get damage() представляет собой геттер — специальный метод, который вычисляет значение свойства каждый раз при обращении к нему. Геттер позволяет динамически рассчитывать урон на основе текущих характеристик персонажа.
Метод attack принимает целевой объект в качестве параметра. Внутри метода происходит вывод сообщения о нанесённом уроне и изменение здоровья цели.
Оператор new создаёт новый экземпляр класса. После создания объекта можно изменять значения его свойств, присваивая новые значения напрямую.
Для вызова метода объекта используется точечная нотация — имя объекта, точка, имя метода и круглые скобки с аргументами.
Объекты и классы
В JavaScript, с появлением ES6 (2015) используется "синтаксический сахар" над прототипным наследованием – классы. Это позволяет писать код в более привычном ООП-стиле. Благодаря классам, может быть создан объект (некоторые объекты уже создаются – элементы DOM), и можно получить доступ к свойствам или методам класса. К примеру, можно вызвать класс.метод() и сразу вызывать уже существующие стандартные возможности, а также создавать свои.
Объект JavaScript может быть пользовательским (со своими свойствами и методами) или объектом DOM.
Их можно расширять при помощи миксинов (путем объединения свойств и методов из одного или нескольких исходных объектов). Микс - смешивать, смешивают поведение нескольких в один объект.

К примеру, так выглядит базовый объект:
// Базовый объект
const Объект = {
имя: "Основной объект",
метод() {
console.log("Это метод основного объекта.");
}
};
Если обратиться через название объекта и точку, можно получать свойства и вызывать методы - Объект.имя или Объект.метод().
Вышеприведенный пример называется простым созданием объекта (литерал):
let obj = {
key: "value",
anotherKey: "AnotherValue"
};
<имя объекта> = {
<ключ>: <значение>,
<ключ>: <значение>,
...
};
Доступ к свойству объекта:
<объект>.<свойство>
Это более сложный тип данных, который можно записать в переменную и придать ему свойства в виде "ключ: “значение”". Это может быть, к примеру, пользователь с присущими ему именем, Email и возрастом:
let user = {
name: "Тимур",
email: "timur@mail.com",
age: 30
};
Почему это называется простым созданием? Потому что есть более сложное - с использованим классов или через функцию конструктор.
Можно создать функцию для того, чтобы создавать объекты по шаблону лишь путем вызова метода-конструктора, которому нужно лишь передать аргументы (соответствующие значениям) и функция сама создаст объект:
function Объект(значение) {
this.ключ = значение;
this.другойКлюч = "значение по умолчанию";
}
let obj1 = new Объект("привет");
let obj2 = new Объект("мир");
console.log(obj1); // { ключ: "привет", другойКлюч: "значение по умолчанию" }
Конструктор будет выступать в роли метода, создающего объект, а команда new означает создание нового объекта. Важно не путать с простым литералом, ведь new Объект это именно функция, а не сам объект.
Объекты нужны для создания комплексного набора данных с разными типами, и при работе с JS в крупных системах, как правило, работа с объектами неизбежна. Важное отличие от примитивов в том, что они работают ссылочно, благодаря чему переменная лишь ссылается на объект. Ссылаться на объект user могут несколько переменных, что позволяет не копировать все значение целиком - память будет использоваться как для одного набора данных. Но давайте пока не будем в это погружаться. Это станет понятно позднее.
У объекта могут быть методы - особые функции, которые являются свойством объекта и хранятся в нём. К примеру, мы сделали объект "собака":
let собака = {
имя: "Тарзан",
лает: function() {
console.log(this.имя + " говорит: Гав-гав!");
}
};
Здесь "лает" является методом объекта "собака". И "this" — это ключевое слово, которое ссылается на сам объект "собака". В дальнейшем мы просто можем вызывать метод через точку:
собака.лает(); // "Тарзан говорит: Гав-гав!"
Вызов метода объекта:
<объект>.<метод>(<аргументы>)
В ES6 появился и более удобный способ:
let собака = {
имя: "Тарзан",
лает() {
console.log(this.имя + " говорит: Гав-гав!");
},
ест(еда) {
console.log(this.имя + " ест " + еда);
}
};
собака.лает(); // Гав-гав!
собака.ест("корм"); // Тарзан ест корм
Причем метод можно добавить и позднее, не обязательно при создании объекта. К примеру, сначала создать объект, потом добавить метод и вызывать его:
let кот = {
имя: "Барсик"
};
// Добавляем метод позже
кот.мяукает = function() {
console.log(this.имя + " говорит: Мяу!");
};
кот.мяукает(); // "Барсик говорит: Мяу!"
Добавление нового свойства или метода к существующему объекту:
<объект>.<новое свойство> = <значение>;
<объект>.<новый метод> = function(<параметры>) { ... };
this — это ссылка на объект, который вызывает функцию. Это называется контекст выполнения - this определяется в момент вызова функции, а не при её создании и зависит от способа вызова функции.
Если вызывать this в методе объекта, то this = сам объект. В больших проектах работа с объектами позволит использовать автодополнение в браузере или IDE, когда можно будет указать "кот." и IDE выведет доступные свойства и методы.
Ранее мы упоминали, что существует деструктивное присваивание — это может быть применено и к объектам.
Пример:
let user = { name: "Боб", age: 30 };
let { name, age } = user;
console.log(name); // "Боб"
console.log(age); // 30
prototype — это механизм наследования в JavaScript, основанный на цепочке прототипов (prototype chain). Каждая функция в JS имеет свойство prototype, которое используется, когда функция используется как конструктор (с new).
prototype — это свойство функции-конструктора.
__proto__ — это свойство объекта, указывающее на его прототип (устаревшее, но работает; современный аналог — Object.getPrototypeOf()).
superclass — это родительский класс, от которого наследуется другой класс (дочерний, или подкласс).
Этот термин чаще используется в контексте классов (ES6+) и наследования через extends.
Объявление класса:
class <ИмяКласса> {
constructor(<параметры>) {
this.<свойство> = <значение>;
...
}
<метод>(<параметры>) {
...
}
}
Создание экземпляра класса:
<экземпляр> = new <ИмяКласса>(<аргументы>);
Наследование класса:
class <ДочернийКласс> extends <РодительскийКласс> {
constructor(<параметры>) {
super(<параметры>);
...
}
<метод>(<параметры>) {
...
}
}
Использование this внутри метода:
this.<свойство>
this.<метод>(<аргументы>)
Деструктуризация объекта — извлечение свойств в переменные; подробнее в типах данных — объект:
const { <свойство1>, <свойство2>, ... } = <объект>;
Создание объекта через функцию-конструктор:
function <ИмяКонструктора>(<параметры>) {
this.<свойство> = <значение>;
...
}
<экземпляр> = new <ИмяКонструктора>(<аргументы>);
Добавление метода в прототип конструктора:
<ИмяКонструктора>.prototype.<метод> = function(<параметры>) {
...
};
Получение прототипа объекта:
Object.getPrototypeOf(<объект>)
Проверка наличия собственного свойства у объекта:
<объект>.hasOwnProperty(<свойство>)
Перебор собственных перечисляемых свойств объекта:
for (let <ключ> in <объект>) {
if (<объект>.hasOwnProperty(<ключ>)) {
...
}
}
Простые примеры прототипов
Представим, что у нас есть объект.
let animal = {
eats: true,
walk() {
console.log("Животное идёт");
}
};
Это классический пример - животное (animal). У него могут быть наследники, к примеру, кролик:
let rabbit = {
jumps: true,
__proto__: animal // устанавливаем прототип
};
Такой "кролик" будет наследовать от animal всё, что у него есть. То есть, для простого получения всех свойств, нам достаточно наследнику добавить свойство __proto__ и указать, от кого будем наследовать.
Теперь мы можем получать все, что есть у родителя:
console.log(rabbit.jumps); // true (своё свойство)
console.log(rabbit.eats); // true (взято из прототипа animal)
rabbit.walk(); // "Животное идёт" (метод из прототипа)
Можно добавить свойство уже после создания объекта:
let animal = { eats: true };
let rabbit = { jumps: true };
rabbit.__proto__ = animal;
for (let prop in rabbit) {
console.log(prop); // "jumps", потом "eats"
}
Цикл for...in, кстати, проходит по всем перечисляемым свойствам, включая те, что пришли по цепочке прототипов.
Например, можно создать некий прототип пользователя, а от него уже создать конкретных пользователей - администратора Антона и безымянного гостя:
Код ITЗагрузка примера кода…
Метод hasOwnProperty нужен, чтобы отфильтровать унаследованные свойства из прототипа. Он возвращает true, если свойство принадлежит непосредственно объекту, а не его прототипу.
for (let prop in rabbit) {
if (rabbit.hasOwnProperty(prop)) { // проверяет: своё ли свойство?
console.log(prop); // только "jumps"
}
}
Таким образом можно отличать "своё" от чужого.
Часто нужны только собственные поля объекта, а не все подряд от предков. Например, при копировании, сериализации в JSON или валидации — не хочется тащить мусор из прототипа.
Можно переопределять методы (overriding):
Код ITЗагрузка примера кода…
Пример с вызовом родительского метода:
Код ITЗагрузка примера кода…
Важно учесть, что если прямо не переопределить метод, он всегда будет родительским:
Код ITЗагрузка примера кода…
Можно переопределить что угодно — методы, свойства. Оригинал в прототипе при этом не меняется. Это называется shadowing (затенение).
Получение свойств и методов объекта
В JavaScript очень часто приходится работать с объектами, чья структура неочевидна — это может быть объект из API, библиотеки, фреймворка (React, Vue, Express), или даже this в сложной цепочке вызовов. И на практике сталкиваться можно с непониманием того, что есть у объекта. Узнать, какие свойства или методы есть у объекта, можно несколькими способами.
- Консоль. Можно открыть консоль в инструментах разработчика (DevTools, F12), поставить точку останова на нужной строке и запустить выполнение кода. После этого, в консоли можно просто написать
thisи поставить точку - после точки будет отображено всё возможное - так работает автодополнение:

- Дерево объекта. Также можно в браузере написать
console.log(myObject); - после чего в консоли браузера увидим интерактивное дерево объекта - по нему можно кликать, раскрывать свойства, смотреть методы.

А если написать console.dir(myObject) — это покажет только свойства и методы, без лишней информации. Можете открыть любой сайт и попробовать протестировать, написав console.log(this) или console.dir(this). Если навести мышкой на объект - подсказка покажет тип и структуру.
Если при поиске объекта, к примеру myObject.test() получаем ошибку "Uncaught TypeError: myObject.test is not a function", значит такой функции нет. А если напишем myObject.test, но такого свойства нет, то получим undefined - "неопределенно".
- Можно использовать методы для перечисления свойств, что позволит программно узнать, что внутри объекта:
Object.keys(obj)вернёт массив собственных перечисляемых свойств ([‘name’, ‘age’]);Object.values(obj)вернёт массив значений свойств ([‘Тимур’, ‘30’]);Object.entries(obj)вернет свойства целиком ([‘name’, ‘Тимур’],[‘age’, ‘30’]);for…inпозволит перебирать свойства, к примеру:
for (let key in user) {
console.log(key, user[key]);
}
Object.getOwnPropertyNames(obj)покажет все собственные свойства, включая неперечисляемые;Reflect.ownKeys(obj)покажет все собственные ключи, включая символы (Symbol) и неперечисляемые.
- VS Code и другие IDE. Если объект имеет типизацию (например, JSDoc, TypeScript или встроен в JS (базовый объект), то VS Code покажет подсказки при наведении и автодополнении. К примеру:
const arr = [1, 2, 3];
arr. // → сразу выпадает список методов: push, pop, map, filter и т.д.
Если же объект из библиотеки или фреймворка, то разумеется, сначала следует прочитать документацию, которая всегда описывает структуру объектов. И опять же, можно смотреть в консоли, как описано выше.
Миксин
Мы можем создать миксины:
// Миксин 1
const Миксин1 = {
миксин1Метод() {
console.log("Это метод из Миксина 1.");
}
};
// Миксин 2
const Миксин2 = {
миксин2Метод() {
console.log("Это метод из Миксина 2.");
}
};
Теперь это два "дополнительных объекта", которые имеют свои методы миксин1Метод() и миксин2Метод().
После этого мы можем либо использовать Object.assign, чтобы скопировать свойства и методы из Миксин1 и Миксин2 в Объект:
// Применяем миксины напрямую через Object.assign
Object.assign(Объект, Миксин1, Миксин2);
// Используем расширенный объект
Объект.метод(); // Это метод основного объекта.
Объект.миксин1Метод(); // Это метод из Миксина 1.
Объект.миксин2Метод(); // Это метод из Миксина 2.
…либо использовать функцию смешивания:
// Функция для смешивания (применения миксинов)
function применитьМиксины(целевойОбъект, ...миксины) {
миксины.forEach(миксин => {
Object.assign(целевойОбъект, миксин);
});
}
// Применяем миксины к объекту
применитьМиксины(Объект, Миксин1, Миксин2);
Применение миксина (копирование свойств из одного объекта в другой):
Object.assign(<целевой объект>, <источник1>, <источник2>, ...);
Функция смешивания актуальна как посредник для случаев, когда объектов может быть несколько и нужно часто применять их к разным объектам, или когда работа ведётся с большим количеством миксинов. Она используется для упрощения процесса объединения свойств и методов из нескольких миксинов в один объект.
// Применяем миксины к объектам
применитьМиксины(Объект1, Миксин1, Миксин2);
применитьМиксины(Объект2, Миксин1);
// Используем расширенные объекты
Объект1.метод(); // Это метод первого объекта.
Объект1.миксин1Метод(); // Это метод из Миксина 1.
Объект1.миксин2Метод(); // Это метод из Миксина 2.
Объект2.метод(); // Это метод второго объекта.
Объект2.миксин1Метод(); // Это метод из Миксина 1.
// Объект2.миксин2Метод(); // Ошибка: метод миксин2Метод не определён, так как Миксин2 не был применён.
Базовые операции с объектами и классами
Объявление класса:
class Person {
// Конструктор (вызывается при создании объекта)
constructor(name, age) {
this.name = name; // Свойство
this.age = age;
}
// Метод
greet() {
return `Привет, я ${this.name}!`;
}
}
Создание объекта (экземпляра класса):
const person = new Person('Том', 25);
console.log(person.greet()); // "Привет, я Том!"
Свойства – это переменные, принадлежащие объекту/классу.
Публичные свойства доступны извне класса:
class Car {
constructor(brand) {
this.brand = brand; // Публичное свойство
}
}
const myCar = new Car('Toyota');
console.log(myCar.brand); // "Toyota"
Интерактивная схема — инкапсуляция (псевдокод). Подробнее: Инкапсуляция.
Play ITЗагрузка интерактивного демо…
Приватные свойства (с префиксом #) доступны только внутри класса:
class User {
#password; // Приватное свойство
constructor(login, password) {
this.login = login;
this.#password = password;
}
}
const user = new User('admin', '12345');
console.log(user.#password); // Ошибка!
Статические свойства (static) принадлежат классу, а не экземплярам:
class MathUtils {
static PI = 3.14; // Статическое свойство
}
console.log(MathUtils.PI); // 3.14
★ Методы – это функции, принадлежащие классу/объекту.
Публичные методы, как и свойства, доступны извне. Приватные методы, как и свойства, доступны внутри класса и имеют префикс #.
★ Пример – класс для работы с API:
Код ITЗагрузка примера кода…
Создание объектов
Литералы объектов
Литерал объекта — это выражение, создающее объект с указанными свойствами и методами:
const user = {
name: "Алексей",
age: 28,
greet() {
return `Привет, меня зовут ${this.name}`;
}
};
Конструкторы через функции
Функция-конструктор создаёт объекты с заданной структурой:
function User(name, age) {
this.name = name;
this.age = age;
this.greet = function() {
return `Привет, меня зовут ${this.name}`;
};
}
const user1 = new User("Мария", 25);
const user2 = new User("Иван", 30);
Object.create()
Метод Object.create() создаёт новый объект с указанным прототипом:
const parent = {
greet() {
return `Привет от ${this.name}`;
}
};
const child = Object.create(parent);
child.name = "Дочерний объект";
console.log(child.greet()); // "Привет от Дочерний объект"
Свойства объектов
Геттеры и сеттеры
Геттеры и сеттеры позволяют контролировать доступ к свойствам:
Код ITЗагрузка примера кода…
Дескрипторы свойств
Дескрипторы описывают поведение свойств объекта:
const obj = {};
Object.defineProperty(obj, 'name', {
value: 'Тест',
writable: false, // нельзя изменить
enumerable: true, // видно в циклах
configurable: false // нельзя удалить или изменить дескриптор
});
obj.name = 'Новое'; // Не сработает
console.log(obj.name); // "Тест"
Полный пример с геттером и сеттером через дескриптор:
Код ITЗагрузка примера кода…
Прототипное наследование
Цепочка прототипов
Каждый объект имеет внутреннее свойство [[Prototype]], ссылающееся на другой объект — прототип. При обращении к свойству объекта, если его нет в самом объекте, поиск продолжается в прототипе:
const animal = {
eats: true,
walk() {
console.log("Животное ходит");
}
};
const rabbit = Object.create(animal);
rabbit.jumps = true;
rabbit.walk(); // "Животное ходит" — метод из прототипа
console.log(rabbit.eats); // true — свойство из прототипа
console.log(rabbit.jumps); // true — собственное свойство
Изменение прототипа
Современный способ изменения прототипа — Object.setPrototypeOf():
const parent = { parentProp: "родитель" };
const child = { childProp: "ребёнок" };
Object.setPrototypeOf(child, parent);
console.log(child.parentProp); // "родитель"
Проверка прототипа
Метод isPrototypeOf() проверяет, является ли объект прототипом другого:
const parent = {};
const child = Object.create(parent);
console.log(parent.isPrototypeOf(child)); // true
console.log(Object.prototype.isPrototypeOf(child)); // true
Методы объекта Object
Object.keys(), values(), entries()
Эти методы возвращают массивы ключей, значений и пар ключ-значение:
const user = {
name: "Олег",
age: 30,
city: "Москва"
};
console.log(Object.keys(user)); // ["name", "age", "city"]
console.log(Object.values(user)); // ["Олег", 30, "Москва"]
console.log(Object.entries(user)); // [["name","Олег"],["age",30],["city","Москва"]]
Object.assign()
Копирует свойства из одного или нескольких источников в целевой объект:
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target); // { a: 1, b: 2, c: 3 }
Глубокое копирование требует рекурсивного подхода:
Код ITЗагрузка примера кода…
Object.defineProperty() и Object.defineProperties()
Определяют или изменяют свойства объекта с точным контролем:
Код ITЗагрузка примера кода…
Object.freeze(), seal(), preventExtensions()
Эти методы ограничивают изменение объекта:
Код ITЗагрузка примера кода…
Object.hasOwnProperty()
Проверяет, является ли свойство собственным (не унаследованным):
const parent = { parentProp: "родитель" };
const child = Object.create(parent);
child.childProp = "ребёнок";
console.log(child.hasOwnProperty("childProp")); // true
console.log(child.hasOwnProperty("parentProp")); // false
console.log("parentProp" in child); // true — проверяет включая прототипы
Function как конструктор
Функция в JavaScript может выступать в роли конструктора при вызове с оператором new:
function Person(name, age) {
this.name = name;
this.age = age;
this.greet = function() {
return `Привет, меня зовут ${this.name}`;
};
}
const person = new Person("Сергей", 35);
console.log(person.name); // "Сергей"
console.log(person.greet()); // "Привет, меня зовут Сергей"
Свойство prototype функции-конструктора становится прототипом созданных объектов:
function Car(brand) {
this.brand = brand;
}
Car.prototype.start = function() {
console.log(`${this.brand} заводится`);
};
const myCar = new Car("Toyota");
myCar.start(); // "Toyota заводится"
Синтаксис классов
Базовый класс
Класс — это шаблон для создания объектов:
Код ITЗагрузка примера кода…
Конструктор
Конструктор инициализирует новый объект:
Код ITЗагрузка примера кода…
Наследование через extends
Интерактивная схема — наследование (псевдокод). Подробнее: Наследование.
Play ITЗагрузка интерактивного демо…
Интерактивная схема — полиморфизм (псевдокод). Подробнее: Полиморфизм.
Play ITЗагрузка интерактивного демо…
Ключевое слово extends создаёт дочерний класс:
Код ITЗагрузка примера кода…
Методы super
Ключевое слово super обращается к методам родительского класса:
Код ITЗагрузка примера кода…
В конструкторе дочернего класса super() должен вызываться до использования this:
class Parent {
constructor(name) {
this.name = name;
}
}
class Child extends Parent {
constructor(name, age) {
super(name); // Обязательно первым
this.age = age;
}
}
Статические методы и поля
Статические члены принадлежат классу, а не экземплярам:
Код ITЗагрузка примера кода…
Приватные поля и методы
Приватные члены доступны только внутри класса:
Код ITЗагрузка примера кода…
Статические блоки инициализации
Статические блоки выполняют сложную инициализацию статических полей:
Код ITЗагрузка примера кода…
Практические примеры
Построение иерархии классов
Код ITЗагрузка примера кода…
Фабрика объектов
Код ITЗагрузка примера кода…
Базовые объекты
Базовые встроенные объекты
★ Базовые встроенные объекты
JavaScript предоставляет стандартные объекты-конструкторы для работы с разными типами данных:
| Объект | Описание | Пример использования |
|---|---|---|
Array | Работа с массивами | [1, 2, 3].map(x => x * 2) |
Boolean | Логические значения | new Boolean(true) |
Math | Математические операции | Math.PI, Math.random() |
Number | Числа и методы | Number.parseInt("42") |
String | Строки и методы | "Hello".toUpperCase() |
Global | Глобальные функции | isNaN(), eval() |
Глобальные свойства
globalThis
Глобальный объект globalThis обеспечивает единый способ доступа к глобальному объекту в разных средах выполнения JavaScript. В браузере глобальным объектом является window, в Node.js — global, а globalThis работает везде одинаково:
// В браузере
console.log(globalThis === window); // true
// В Node.js
console.log(globalThis === global); // true
// Универсальный доступ
globalThis.myGlobalVar = "Значение";
console.log(globalThis.myGlobalVar); // "Значение"
Infinity
Свойство Infinity представляет бесконечность — числовое значение, большее любого другого числа:
console.log(Infinity); // Infinity
console.log(10 / 0); // Infinity
console.log(Infinity + 1); // Infinity
console.log(Infinity * 2); // Infinity
console.log(Infinity - Infinity); // NaN
// Проверка на бесконечность
console.log(isFinite(Infinity)); // false
console.log(isFinite(100)); // true
console.log(Number.isFinite(Infinity)); // false
Отрицательная бесконечность:
console.log(-Infinity); // -Infinity
console.log(-10 / 0); // -Infinity
NaN
NaN (Not-a-Number) представляет результат неопределённой или некорректной математической операции:
console.log(NaN); // NaN
console.log(0 / 0); // NaN
console.log(Math.sqrt(-1)); // NaN
console.log(parseInt("текст")); // NaN
console.log("строка" * 5); // NaN
Особенность NaN — он не равен ничему, включая самого себя:
console.log(NaN === NaN); // false
console.log(NaN == NaN); // false
Проверка на NaN:
console.log(isNaN(NaN)); // true
console.log(isNaN("текст")); // true — преобразует в число сначала
console.log(isNaN(123)); // false
// Более точная проверка
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("текст")); // false — не преобразует
console.log(Number.isNaN(123)); // false
undefined
undefined означает, что переменная объявлена, но не инициализирована, или свойство объекта отсутствует:
let x;
console.log(x); // undefined
console.log(typeof x); // "undefined"
const obj = {};
console.log(obj.nonExistentProperty); // undefined
function noReturn() {}
console.log(noReturn()); // undefined
Проверка на undefined:
let value;
if (value === undefined) {
console.log("Значение не определено");
}
// Безопасная проверка
if (typeof value === "undefined") {
console.log("Переменная не определена");
}
Глобальные функции
eval()
Функция eval() выполняет строку как код JavaScript:
const code = "console.log('Привет, мир!')";
eval(code); // "Привет, мир!"
const result = eval("2 + 2 * 3");
console.log(result); // 8
const x = 10;
const y = 20;
console.log(eval("x + y")); // 30
Опасности использования eval():
- Выполнение непроверенного кода создаёт уязвимости
- Замедляет выполнение программы
- Нарушает безопасность приложения
- Затрудняет отладку кода
Безопасные альтернативы:
// Вместо eval для вычисления математических выражений
const expression = "2 + 2 * 3";
const result = Function('"use strict";return (' + expression + ')')();
console.log(result); // 8
// Для парсинга JSON
const jsonString = '{"name":"Иван","age":30}';
const obj = JSON.parse(jsonString);
console.log(obj.name); // "Иван"
isFinite()
Функция isFinite() проверяет, является ли значение конечным числом:
console.log(isFinite(123)); // true
console.log(isFinite(-123)); // true
console.log(isFinite(0)); // true
console.log(isFinite(Infinity)); // false
console.log(isFinite(-Infinity)); // false
console.log(isFinite(NaN)); // false
// Строки преобразуются в числа
console.log(isFinite("123")); // true
console.log(isFinite("12.5")); // true
console.log(isFinite("текст")); // false
console.log(isFinite("")); // true (пустая строка → 0)
Более строгая проверка через Number.isFinite():
console.log(Number.isFinite(123)); // true
console.log(Number.isFinite("123")); // false — не преобразует строку
console.log(Number.isFinite(NaN)); // false
isNaN()
Функция isNaN() проверяет, является ли значение NaN:
console.log(isNaN(NaN)); // true
console.log(isNaN("текст")); // true — "текст" → NaN
console.log(isNaN(123)); // false
console.log(isNaN("123")); // false — "123" → 123
console.log(isNaN("")); // false — пустая строка → 0
console.log(isNaN(" ")); // false — пробел → 0
Разница между isNaN() и Number.isNaN():
console.log(isNaN("привет")); // true
console.log(Number.isNaN("привет")); // false — не преобразует
console.log(isNaN(NaN)); // true
console.log(Number.isNaN(NaN)); // true
console.log(isNaN(undefined)); // true
console.log(Number.isNaN(undefined)); // false
parseInt()
Функция parseInt() преобразует строку в целое число:
console.log(parseInt("42")); // 42
console.log(parseInt("42px")); // 42
console.log(parseInt("10.5")); // 10 — дробная часть отбрасывается
console.log(parseInt("0xFF")); // 255 — шестнадцатеричное
console.log(parseInt("10", 2)); // 2 — двоичная система
console.log(parseInt("10", 8)); // 8 — восьмеричная система
console.log(parseInt("10", 16)); // 16 — шестнадцатеричная система
// Обработка некорректных значений
console.log(parseInt("текст")); // NaN
console.log(parseInt("")); // NaN
console.log(parseInt(" 42 ")); // 42 — пробелы игнорируются
Явное указание системы счисления:
console.log(parseInt("10", 10)); // 10
console.log(parseInt("FF", 16)); // 255
console.log(parseInt("77", 8)); // 63
console.log(parseInt("1010", 2)); // 10
parseFloat()
Функция parseFloat() преобразует строку в число с плавающей точкой:
console.log(parseFloat("3.14")); // 3.14
console.log(parseFloat("3.14px")); // 3.14
console.log(parseFloat("10")); // 10
console.log(parseFloat("10.00")); // 10
console.log(parseFloat("2.5e3")); // 2500 — экспоненциальная запись
console.log(parseFloat("Infinity")); // Infinity
// Обработка некорректных значений
console.log(parseFloat("текст")); // NaN
console.log(parseFloat("")); // NaN
console.log(parseFloat(" 3.14 ")); // 3.14
Разница между parseInt() и parseFloat():
console.log(parseInt("10.99")); // 10 — только целая часть
console.log(parseFloat("10.99")); // 10.99 — сохраняет дробную часть
console.log(parseInt("3.5e2")); // 3
console.log(parseFloat("3.5e2")); // 350
Кодирование и декодирование URI
Функции для работы с URL и URI:
encodeURI()
Кодирует полный URI, сохраняя разделители:
const uri = "https://сайт.рф/путь?параметр=значение с пробелами";
console.log(encodeURI(uri));
// "https://сайт.рф/путь?параметр=значение%20с%20пробелами"
// Сохраняет разделители URI
console.log(encodeURI("https://example.com/путь/страница"));
// "https://example.com/%D0%BF%D1%83%D1%82%D1%8C/%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0"
encodeURIComponent()
Кодирует компонент URI, включая разделители:
Код ITЗагрузка примера кода…
decodeURI()
Декодирует полный URI:
const encoded = "https://сайт.рф/путь?параметр=значение%20с%20пробелами";
console.log(decodeURI(encoded));
// "https://сайт.рф/путь?параметр=значение с пробелами"
decodeURIComponent()
Декодирует компонент URI:
Код ITЗагрузка примера кода…
Разница между encodeURI() и encodeURIComponent():
const url = "https://example.com/путь?параметр=значение с пробелами";
console.log(encodeURI(url));
// "https://example.com/%D0%BF%D1%83%D1%82%D1%8C?параметр=значение%20с%20пробелами"
// Символы ? и = сохраняются
console.log(encodeURIComponent(url));
// "https%3A%2F%2Fexample.com%2F%D0%BF%D1%83%D1%82%D1%8C%3F%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80%3D%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%20%D1%81%20%D0%BF%D1%80%D0%BE%D0%B1%D0%B5%D0%BB%D0%B0%D0%BC%D0%B8"
// Все специальные символы кодируются
Устаревшие функции
escape() и unescape()
Эти функции считаются устаревшими и не должны использоваться в современном коде:
// Устаревший способ
const oldEncoded = escape("Привет мир!");
console.log(oldEncoded); // "%u041F%u0440%u0438%u0432%u0435%u0442%20%u043C%u0438%u0440%21"
const oldDecoded = unescape(oldEncoded);
console.log(oldDecoded); // "Привет мир!"
// Современная замена
const newEncoded = encodeURIComponent("Привет мир!");
console.log(newEncoded); // "%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82%20%D0%BC%D0%B8%D1%80%21"
const newDecoded = decodeURIComponent(newEncoded);
console.log(newDecoded); // "Привет мир!"
Фундаментальные объекты
Boolean
Объект Boolean представляет логическое значение:
Код ITЗагрузка примера кода…
Разница между примитивом и объектом:
Код ITЗагрузка примера кода…
Symbol
Символы — это уникальные идентификаторы:
// Создание символов
const sym1 = Symbol();
const sym2 = Symbol("описание");
const sym3 = Symbol("описание");
console.log(sym1); // Symbol()
console.log(sym2); // Symbol(описание)
console.log(sym3); // Symbol(описание)
// Символы всегда уникальны
console.log(sym2 === sym3); // false
console.log(Symbol() === Symbol()); // false
Глобальный реестр символов:
const sym1 = Symbol.for("ключ");
const sym2 = Symbol.for("ключ");
console.log(sym1 === sym2); // true — один и тот же символ из реестра
console.log(Symbol.keyFor(sym1)); // "ключ"
Использование символов как ключей свойств:
Код ITЗагрузка примера кода…
Символы как константы:
Код ITЗагрузка примера кода…
Error и его подтипы
Объект Error представляет ошибку во время выполнения:
Код ITЗагрузка примера кода…
EvalError
Ошибка при работе с функцией eval():
try {
throw new EvalError("Ошибка при вычислении");
} catch (error) {
console.log(error.name); // "EvalError"
console.log(error.message); // "Ошибка при вычислении"
}
RangeError
Ошибка при выходе за пределы допустимого диапазона:
Код ITЗагрузка примера кода…
ReferenceError
Ошибка при обращении к несуществующей переменной:
Код ITЗагрузка примера кода…
SyntaxError
Ошибка синтаксиса в коде:
Код ITЗагрузка примера кода…
TypeError
Ошибка при применении операции к неподходящему типу:
Код ITЗагрузка примера кода…
URIError
Ошибка при работе с функциями кодирования URI:
Код ITЗагрузка примера кода…
AggregateError
Представляет несколько ошибок одновременно:
Код ITЗагрузка примера кода…
SuppressedError
Представляет ошибку, подавленную другой ошибкой (новый функционал):
Код ITЗагрузка примера кода…
InternalError (не стандартный)
Нестандартный объект ошибки, используемый в некоторых средах:
// Этот объект не является частью стандарта ECMAScript
// Может встречаться в старых версиях некоторых браузеров
try {
// Очень глубокая рекурсия
function recurse() {
recurse();
}
recurse();
} catch (error) {
console.log(error.name); // Может быть "InternalError" или "RangeError"
}
Практические примеры
Валидация данных с использованием глобальных функций
Код ITЗагрузка примера кода…
Создание кастомных ошибок
Код ITЗагрузка примера кода…
Особенности базовых объектов
★ Массив – основные методы:
| Метод | Описание | Пример |
|---|---|---|
push() / pop() | Добавить/удалить элемент в конец | arr.push(4) → [1,2,3,4] |
shift() / unshift() | Удалить/добавить в начало | arr.unshift(0) → [0,1,2,3] |
slice() | Копирует часть массива | arr.slice(1,3) → [2,3] |
splice() | Удаляет/заменяет элементы | arr.splice(1,1) → [1,3] |
map() | Преобразует массив | [1,2].map(x => x*2) → [2,4] |
filter() | Фильтрует элементы | [1,2,3].filter(x => x>1) → [2,3] |
reduce() | Сворачивает массив в одно значение | [1,2].reduce((a,b) => a+b) → 3 |
find() | Находит первый подходящий элемент | [1,2,3].find(x => x>1) → 2 |
sort() | Сортирует массив | [3,1].sort() → [1,3] |
forEach(fn) | Выполняет функцию для каждого элемента (ничего не возвращает) | arr.forEach(el => console.log(el)) |
includes(value) | Проверяет, есть ли элемент в массиве | [1,2].includes(2) → true |
indexOf(value) | Возвращает индекс элемента или -1, если не найден | [1,2,3].indexOf(2) → 1 |
some(fn) | Проверяет, существует ли хотя бы один подходящий элемент | [1,2].some(x => x > 1) → true |
every(fn) | Проверяет, все ли элементы соответствуют условию | [2,3].every(x => x > 1) → true |
join(separator) | Преобразует массив в строку с указанным разделителем | [1,2,3].join('-') → "1-2-3" |
reverse() | Разворачивает массив (мутирует оригинал) | [1,2,3].reverse() → [3,2,1] |
flat(n) | Расплющивает вложенные массивы на n уровней | [1, [2, [3]]].flat(2) → [1,2,3] |
isArray()(статический) | Проверяет, является ли значение массивом | Array.isArray([1]) → true |
★ Числа – основные методы и свойства:
| Метод/ Свойство | Описание | Пример |
|---|---|---|
Number.parseInt() | Преобразует строку в целое число | parseInt("42") → 42 |
Number.parseFloat() | Преобразует в дробное число | parseFloat("3.14") → 3.14 |
toFixed(n) | Округляет до n знаков после запятой | 3.1415.toFixed(2) → "3.14" |
toString() | Преобразует число в строку | 42.toString() → "42" |
Math.random() | Случайное число от 0 до 1 | Math.random() → 0.123 |
Math.round() | Округление до ближайшего целого | Math.round(3.6) → 4 |
Math.floor(x) | Округляет вниз до целого | Math.floor(3.9) → 3 |
Math.ceil(x) | Округляет вверх до целого | Math.ceil(3.1) → 4 |
Math.trunc(x) | Убирает дробную часть, не округляя | Math.trunc(3.9) → 3 |
Number.isNaN(value) | Проверяет, является ли значение NaN | Number.isNaN(NaN) → true |
Number.isFinite(value) | Проверяет, является ли значение конечным числом | Number.isFinite(Infinity) → false |
Number.isInteger(value) | Проверяет, является ли число целым | Number.isInteger(42) → true |
Math.pow(x, y) | Возводит x в степень y | Math.pow(2, 3) → 8 |
Math.sqrt(x) | Квадратный корень из числа | Math.sqrt(16) → 4 |
Math.min(...values) | Находит минимальное число | Math.min(1, 2, 3) → 1 |
Math.max(...values) | Находит максимальное число | Math.max(1, 2, 3) → 3 |
Number.MIN_VALUE | Минимально возможное положительное число | Number.MIN_VALUE → 5e-324 |
Number.MAX_VALUE | Максимально возможное число | Number.MAX_VALUE → 1.7976...e+308 |
★ Строки – основные методы (разбор с примерами и шпаргалкой по группам — типы данных, методы строк):
| Метод | Описание | Пример |
|---|---|---|
length | Длина строки | "hello".length → 5 |
toUpperCase() | Преобразует в верхний регистр | "Hi".toUpperCase() → "HI" |
toLowerCase() | Преобразует в нижний регистр | "Hi".toLowerCase() → "hi" |
includes() | Проверяет наличие подстроки | "hello".includes("ell") → true |
split() | Разделяет строку в массив | "a,b,c".split(",") → ["a","b","c"] |
trim() | Удаляет пробелы с обоих концов | " hi ".trim() → "hi" |
replace() | Заменяет подстроку | "hi".replace("i", "ello") → "hello" |
indexOf(substring) | Возвращает индекс первого вхождения подстроки, или -1, если не найдено | "hello".indexOf("e") → 1 |
lastIndexOf(substring) | Возвращает индекс последнего вхождения подстроки | "abacaba".lastIndexOf("a") → 6 |
slice(start, end?) | Возвращает часть строки между начальным и конечным индексами (не включая конец) | "hello".slice(1,4) → "ell" |
substring(start, end?) | То же, что и slice, но не поддерживает отрицательные значения | "hello".substring(1,4) → "ell" |
charAt(index) | Возвращает символ по указанному индексу | "hello".charAt(0) → "h" |
startsWith(prefix) | Проверяет, начинается ли строка с указанной подстроки | "hello".startsWith("he") → true |
endsWith(suffix) | Проверяет, заканчивается ли строка указанной подстрокой | "hello".endsWith("lo") → true |
repeat(count) | Повторяет строку заданное число раз | "ha".repeat(3) → "hahaha" |
★ Глобальные функции – функции, которые доступны в глобальной области видимости:
| Функция | Описание | Пример |
|---|---|---|
isNaN() | Проверяет, является ли значение NaN | isNaN("text") → true |
parseInt() | Аналог Number.parseInt() | parseInt("42px") → 42 |
parseFloat() | Аналог Number.parseFloat() | parseFloat("3.14.15") → 3.14 |
eval() | Выполняет строку как код (опасно!) | eval("2+2") → 4 |
encodeURI() | Кодирует URL | encodeURI("https://сайт.рф") → "https://%D1%81%D0%B0%D0%B9%D1%82.%D1%80%D1%84" |
★ Работа с датами (Date)
Date – объект, который используется для работы с временем.
const now = new Date(); // Текущая дата
console.log(now.getFullYear()); // Год (2023)
console.log(now.getMonth()); // Месяц (0-11)
console.log(now.getDate()); // День месяца (1-31)
console.log(now.getHours()); // Часы (0-23)
console.log(now.toLocaleString()); // "12.01.2023, 14:30:00"
DOM
★ DOM (Document Object Model)
DOM – программное представление HTML-документа в виде дерева объектов. Объект Document представляет собой весь HTML-документ и является корневым узлом дерева DOM. Он предоставляет методы и свойства для взаимодействия с содержимым страницы — поиска элементов, создания новых узлов, изменения содержимого, управления стилями и многим другим.
Основные сущности DOM:
| Сущность | Описание |
|---|---|
Document | Корень DOM (весь документ) |
Element | HTML-элемент |
Attr | Атрибут элемента |
Text | Текстовый узел |
Comment | Комментарий |
DocumentFragment | Легковесный "контейнер" для DOM |
Node | Базовый класс для всех узлов |
NodeList | Коллекция узлов |
NamedNodeMap | Коллекция атрибутов элемента |
★ Свойства Document:
| Свойство | Описание | Пример |
|---|---|---|
document.documentElement Ссылка на корневой элемент <html> | document.documentElement.tagName → "HTML" | |
document.head | Ссылка на элемент <head> | document.head.appendChild(myScript) |
document.body | Ссылка на элемент <body> | document.body.innerHTML = "<h1>Привет</h1>" |
document.title | Получает или устанавливает заголовок страницы (<title>) | document.title = "Новая страница" |
document.URL | Возвращает полный URL текущего документа | console.log(document.URL) |
document.location | Объект Location, содержащий информацию о текущем адресе | document.location.href |
document.links | Коллекция всех гиперссылок (<a>) на странице | document.links[0].href |
document.images | Коллекция всех изображений (<img>) на странице | document.images.length |
document.forms | Коллекция всех форм на странице | document.forms.loginForm |
Методы поиска элементов:
| Метод | Пример | Возвращает |
|---|---|---|
getElementById() | document.getElementById('app') | Один Element |
getElementsByClassName() | document.getElementsByClassName('item') | HTMLCollection |
getElementsByTagName() | document.getElementsByTagName('div') | HTMLCollection |
querySelector() | document.querySelector('.btn') | Первый подходящий Element |
querySelectorAll() | document.querySelectorAll('p') | NodeList |
Методы создания элементов:
- createElement() – создаёт элемент;
- createTextNode() –создаёт текстовый узел;
- createComment() – создаёт комментарий;
- createAttribute() – создаёт объект атрибута (реже
setAttributeна элементе).
★ Обход и изменение дерева (узлы):
| API | Пример | Действие |
|---|---|---|
appendChild(node) | parent.appendChild(child) | Добавить ребёнка в конец |
insertBefore(new, ref) | parent.insertBefore(li, first) | Вставить перед ref |
removeChild(node) | parent.removeChild(child) | Удалить дочерний узел |
replaceChild(new, old) | parent.replaceChild(newLi, oldLi) | Заменить ребёнка |
hasChildNodes() | ul.hasChildNodes() | Есть ли дочерние узлы |
children / childNodes | ul.children | Элементы / все узлы (свойства) |
firstElementChild, lastElementChild | ul.firstElementChild | Первый / последний элемент-ребёнок |
parentNode | span.parentNode | Родитель |
nextElementSibling, previousElementSibling | li.nextElementSibling | Соседние элементы |
nodeType | node.nodeType === 1 | 1 — Element, 3 — Text |
См. шпаргалку и примеры в Работа с HTML, события — События.
★ Свойства Element:
| Свойство | Значение |
|---|---|
element.id | значение атрибута id |
element.className | строка классов (class="...") |
element.classList | объект для работы с классами (методы: add(), remove(), toggle()) |
element.innerHTML | HTML-содержимое внутри тега |
element.outerHTML | элемент целиком с открывающим и закрывающим тегом |
element.textContent | текст (без HTML-тегов) |
element.style | доступ к CSS-стилям |
★ Методы:
| Метод | Пример | Действие |
|---|---|---|
| getAttribute() | div.getAttribute('data-id') | Получить атрибут |
| setAttribute() | div.setAttribute('data-test', '123') | Установить атрибут |
| removeAttribute() | div.removeAttribute('hidden') | Удалить атрибут |
| hasAttribute() | div.hasAttribute('disabled') | Проверить наличие атрибута |
| append() / prepend() | div.append(newElement) | Добавить элемент |
| remove() | div.remove() | Удалить элемент |
| closest() | div.closest('.parent') | Найти ближайший родительский элемент |
Прочие объекты
Браузерные объекты
★ Браузерные объекты
Браузерные объекты – объекты, предоставляемые для работы с окружением:
| Объект | Описание |
|---|---|
| Window | Глобальный объект (вкладка браузера) |
| Navigator | Информация о браузере |
| Screen | Данные об экране |
| History | Управление историей |
| Location | URL страницы |
Свойства Window:
| Свойства | Описание | Пример |
|---|---|---|
| window.innerWidth | Ширина области просмотра (px) | window.innerWidth → 1200 |
| window.innerHeight | Высота области просмотра (px) | window.innerHeight → 800 |
| window.outerWidth | Ширина всего окна браузера (px) | window.outerWidth → 1400 |
| window.outerHeight | Высота всего окна браузера (px) | window.outerHeight → 900 |
| window.location | Объект Location (URL страницы) | window.location.href |
| window.document | Объект Document (DOM) | window.document.title |
| window.localStorage | Локальное хранилище данных | window.localStorage.setItem('key', 'value') |
Методы:
| Метод | Описание | Пример |
|---|---|---|
| window.alert() | Показывает alert-окно | window.alert("Привет!") |
| window.open() | Открывает новое окно/вкладку | window.open("https://google.com") |
| window.scrollTo() | Прокручивает страницу | window.scrollTo(0, 100) |
| window.setTimeout() | Выполняет код с задержкой | setTimeout(() => {}, 1000) |
| window.fetch() | Отправляет HTTP-запрос | fetch("https://api.example.com") |
★ Графика: Canvas
Объект CanvasRenderingContext2D позволяет рисовать на <canvas>. Полный разбор API — в Canvas 2D.
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'red';
ctx.fillRect(10, 10, 100, 100); // Рисуем красный квадрат
Работа с файлами и системой
В браузере и Node.js есть объекты для работы с файлами, сетью и процессами.
В браузере:
File API: Чтение файлов через <input type= "file">:
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
console.log(file.name); // Имя файла
});
Основные методы/свойства File API:
- files – список выбранных файлов;
- FileReader – чтение содержимого файла;
- Blob – бинарные данные файла.
В Node.js:
- File System (fs) — чтение/запись файлов – readFile, writeFile, promises;
- HTTP/NET: создание серверов – createServer, request;
- Buffer/Stream: работа с бинарными данными – Buffer.from(), stream.pipe();
- Process — процессы – argv, cwd, exit.
И да, метода JSON.statham() нет. Вроде бы.
Структурированные данные
ArrayBuffer и SharedArrayBuffer
ArrayBuffer представляет собой буфер данных фиксированной длины, используемый для хранения бинарных данных:
// Создание буфера размером 16 байт
const buffer = new ArrayBuffer(16);
console.log(buffer.byteLength); // 16
console.log(buffer); // ArrayBuffer { byteLength: 16 }
Для работы с данными внутри буфера используются типизированные массивы:
Код ITЗагрузка примера кода…
SharedArrayBuffer позволяет разделять буфер памяти между несколькими потоками выполнения (например, с помощью веб-воркеров):
// Создание разделяемого буфера
const sharedBuffer = new SharedArrayBuffer(1024);
// Создание представления
const sharedArray = new Int32Array(sharedBuffer);
// Запись данных
sharedArray[0] = 42;
sharedArray[1] = 100;
DataView
DataView предоставляет низкоуровневый интерфейс для чтения и записи данных произвольного типа в ArrayBuffer:
Код ITЗагрузка примера кода…
Указание порядка байтов (endianness):
const buffer = new ArrayBuffer(4);
const view = new DataView(buffer);
// Запись с указанием порядка байтов
view.setInt32(0, 0x12345678, true); // little-endian
console.log(view.getInt32(0, true)); // 305419896
view.setInt32(0, 0x12345678, false); // big-endian
console.log(view.getInt32(0, false)); // 305419896
Atomics
Atomics предоставляет атомарные операции для работы с разделяемой памятью, обеспечивая потокобезопасность:
Код ITЗагрузка примера кода…
Синхронизация потоков с помощью wait и notify:
// В основном потоке
Atomics.store(sharedArray, 0, 0);
// В воркере
Atomics.wait(sharedArray, 0, 0); // Ожидает, пока значение не изменится
console.log("Продолжение выполнения");
// В основном потоке после изменения
Atomics.store(sharedArray, 0, 1);
Atomics.notify(sharedArray, 0); // Пробуждает ожидающий воркер
JSON
Объект JSON предоставляет методы для преобразования данных в формат JSON и обратно:
Код ITЗагрузка примера кода…
Форматирование при сериализации:
Код ITЗагрузка примера кода…
Использование функции-замены (replacer):
Код ITЗагрузка примера кода…
Управление памятью
WeakRef
WeakRef создаёт слабую ссылку на объект, позволяя сборщику мусора удалить объект, если на него нет других сильных ссылок:
Код ITЗагрузка примера кода…
FinalizationRegistry
FinalizationRegistry регистрирует колбэк, который вызывается после удаления объекта сборщиком мусора:
Код ITЗагрузка примера кода…
Практическое применение для управления ресурсами:
Код ITЗагрузка примера кода…
Абстракции управления
Iterator и AsyncIterator
Итераторы предоставляют стандартный способ перебора элементов коллекции:
Код ITЗагрузка примера кода…
Асинхронные итераторы для работы с асинхронными данными:
Код ITЗагрузка примера кода…
Promise
Promise представляет результат асинхронной операции:
Код ITЗагрузка примера кода…
Статические методы Promise:
Код ITЗагрузка примера кода…
Generator и GeneratorFunction
Генераторы позволяют приостанавливать и возобновлять выполнение функции:
Код ITЗагрузка примера кода…
Генератор с параметрами:
function* counter() {
let count = 0;
while (true) {
const increment = yield count;
count += increment || 1;
}
}
const gen = counter();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next(5).value); // 6
console.log(gen.next(10).value); // 16
Делегирование генераторов:
function* gen1() {
yield 1;
yield 2;
}
function* gen2() {
yield 3;
yield* gen1(); // Делегирование
yield 4;
}
const gen = gen2();
console.log([...gen]); // [3, 1, 2, 4]
AsyncGenerator и AsyncGeneratorFunction
Асинхронные генераторы объединяют функциональность генераторов и промисов:
async function* asyncNumberGenerator() {
yield 1;
await new Promise(resolve => setTimeout(resolve, 1000));
yield 2;
await new Promise(resolve => setTimeout(resolve, 1000));
yield 3;
}
(async () => {
for await (let num of asyncNumberGenerator()) {
console.log(num); // 1, затем 2 (через 1с), затем 3 (через 2с)
}
})();
Практическое применение для потоковой загрузки данных:
async function* fetchPages(url, pages) {
for (let page = 1; page <= pages; page++) {
const response = await fetch(`${url}?page=${page}`);
const data = await response.json();
yield data;
}
}
(async () => {
for await (const pageData of fetchPages("/api/items", 3)) {
console.log("Загружена страница:", pageData);
}
})();
AsyncFunction
AsyncFunction — это конструктор для создания асинхронных функций динамически:
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
const asyncSum = new AsyncFunction('a', 'b', 'return a + b');
asyncSum(5, 3).then(result => console.log(result)); // 8
DisposableStack и AsyncDisposableStack
Эти объекты упрощают управление ресурсами, требующими очистки:
Код ITЗагрузка примера кода…
Асинхронная версия:
Код ITЗагрузка примера кода…
Рефлексия
Reflect
Reflect предоставляет методы для выполнения операций над объектами в функциональном стиле:
Код ITЗагрузка примера кода…
Proxy
Proxy позволяет перехватывать и переопределять операции над объектами:
Код ITЗагрузка примера кода…
Валидация данных через прокси:
Код ITЗагрузка примера кода…
Создание неизменяемого объекта:
Код ITЗагрузка примера кода…
Интернационализация
Intl
Объект Intl предоставляет интернационализированные функции форматирования:
// Текущая локаль
console.log(Intl.getCanonicalLocales("en-US")); // ["en-US"]
console.log(Intl.getCanonicalLocales("RU")); // ["ru"]
Intl.Collator
Collator обеспечивает сортировку строк с учётом локали:
Код ITЗагрузка примера кода…
Intl.DateTimeFormat
Форматирование дат и времени:
Код ITЗагрузка примера кода…
Форматирование для разных локалей:
const date = new Date(2024, 0, 15);
console.log(new Intl.DateTimeFormat("en-US").format(date)); // "1/15/2024"
console.log(new Intl.DateTimeFormat("de-DE").format(date)); // "15.1.2024"
console.log(new Intl.DateTimeFormat("ja-JP").format(date)); // "2024/1/15"
console.log(new Intl.DateTimeFormat("zh-CN").format(date)); // "2024/1/15"
Intl.NumberFormat
Форматирование чисел:
Код ITЗагрузка примера кода…
Intl.RelativeTimeFormat
Форматирование относительного времени:
Код ITЗагрузка примера кода…
Intl.ListFormat
Форматирование списков:
Код ITЗагрузка примера кода…
Intl.PluralRules
Определение формы множественного числа:
Код ITЗагрузка примера кода…
Intl.DisplayNames
Отображение названий локалей, регионов и языков:
Код ITЗагрузка примера кода…
Intl.Segmenter
Сегментация текста на графемы, слова или предложения:
Код ITЗагрузка примера кода…
Intl.Locale
Работа с локалями:
Код ITЗагрузка примера кода…
Практические примеры
Создание кэша с автоматической очисткой
Код ITЗагрузка примера кода…
Интернационализированный форматтер дат
Код ITЗагрузка примера кода…
Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.
Навигация по теме объектов
Статья большая, поэтому удобнее изучать ее слоями:
- Сначала базовые объекты, свойства и методы.
- Потом прототипы и наследование.
- Затем дескрипторы, иммутабельность и метапрограммирование.
Практический чеклист по объектам в проекте:
- отделяйте данные от поведения (DTO vs доменные объекты);
- замораживайте конфиги (
Object.freeze), если они не должны меняться; - избегайте глубоких мутаций без необходимости;
- для сравнения структур пишите явную логику, а не
===.
const appConfig = Object.freeze({
apiBaseUrl: "/api",
retryCount: 3
});
Продолжение: