Типы данных в JavaScript
Разбираемся, как JavaScript видит числа, строки и все остальное, пытаемся разобраться в его логике и не сойти с ума.


Иллюстрация: Оля Ежак для Skillbox Media
В JavaScript мы всё время работаем с данными — что-то передаём, сравниваем, складываем, сохраняем в переменные. Но данные в этом языке могут обрабатываться самыми непредсказуемыми способами. В JavaScript может быть, например, вот так:
console.log("5" - 1); // 4
console.log("5" + 1); // 51
// Живите теперь с этим
В одном случае получилась строка, а в другом — число. Всё дело в типах данных и в том, как язык их преобразует.
Числа, строки, булевы значения, объекты и так далее — это разные типы данных. Каждый тип ведёт себя по-своему, и JavaScript обрабатывает их по-разному. Если не учитывать это, жизнь ваша будет полна странностей и неожиданностей.
В этой статье мы расскажем, какие типы данных есть в JavaScript, как они работают и как их правильно использовать на практике.
Содержание:
- Какие типы данных есть в JavaScript
- Семь примитивных типов данных
- object — ссылочный тип данных
- Как узнать, какой тип у переменной
- Как JavaScript сам меняет типы и как этим управлять
- Интересные факты
- Практика: как работают типы данных
- Полезные материалы
Какие типы данных есть в JavaScript
В JavaScript всего восемь типов данных. Все они делятся на две большие группы — примитивные и ссылочные.
Знать разницу между ними очень важно. Именно на этом строится логика JavaScript, и большинство неожиданных багов происходит из-за путаницы между этими типами.
Примитивы
Примитивные типы ведут себя просто: они передаются по значению и не изменяются напрямую. Если вы копируете примитив, вы получаете новую переменную, а не доступ к оригиналу.
Представьте себе: вы записали чей-то номер телефона на листок бумаги. Друг сделал себе копию, но потом зачем-то стёр последние цифры. Его копия изменилась, а на вашем листе всё осталось как было.
Вот пример:
let a = 10;
let b = a; // b -- это просто копия значения a
b = 20;
console.log(a); // 10
console.log(b); // 20
Значения a и b независимы. Изменения одной переменной никак не влияют на другую.
Ссылочные типы
А вот ссылочные типы передаются по ссылке. Это как поделиться доступом к «Google Документу»: если кто-то внесет правки, их увидят сразу все.
let obj1 = { name: "Вася" };
let obj2 = obj1;
obj2.name = "Ася";
console.log(obj1.name); // "Ася"
Переменные obj1 и obj2 ссылаются на один и тот же объект в памяти. Изменили один — изменился и другой.
Семь примитивных типов данных
Семь из восьми типов данных в JavaScript — это примитивы. Они так называются, потому что это простые, базовые и неизменные единицы данных.
Вот список:
- string — строки,
- number — числа,
- bigint — большие числа,
- boolean — логические значения,
- undefined — переменная есть, но значения нет,
- null — значение должно быть пустым,
- symbol — уникальный идентификатор.
String (строка)
Строка — это набор символов, идущих друг за другом. Например: 'Привет', '123', 'аbс!'. Строки неизменяемы. На практике это значит, что если вы меняете строку, на самом деле создаётся новая, а старая остаётся такой же, какой была.
Пример:
let str = "Привет";
str.toUpperCase(); // переводит текст в верхний регистр и возвращает "ПРИВЕТ"
console.log(str); // всё равно "Привет"
Метод toUpperCase() вернул новую строку, но в переменную str мы её не записали — и строка осталась прежней.
Если вы хотите сохранить изменённую строку, нужно явно присвоить результат переменной:
str = str.toUpperCase(); // теперь str -- это "ПРИВЕТ"

Читайте также:
Number (число)
В JavaScript все числа, кроме очень больших, относятся к одному типу данных: number. Неважно, пишете вы 10, 3.14 или -500, всё это — один тип. В других языках вроде C++ или Java есть разные типы для целых и дробных чисел, но в JavaScript один number на все случаи.
При этом в JavaScript числа хранятся в двоичном виде. Из-за этого далеко не каждое десятичное число можно точно записать. Например, 0.1 и 0.2 в двоичном виде бесконечные и не вполне совпадают с десятичными значениями. Поэтому иногда происходят странности:
console.log(0.1 + 0.2); // 0.30000000000000004
Это не ошибка, а особенность хранения чисел в памяти. Такое бывает почти во всех языках программирования, просто не всегда бросается в глаза. Чтобы избежать проблем, такие числа обычно округляют.
У number есть свои ограничения. Все числа внутри него лежат в пределах от ‑(2⁵³ - 1) до 2⁵³ - 1 — это примерно от минус 9 квадриллионов до 9 квадриллионов. Если выйти за этот предел, число может начать терять точность. Проверить границы можно так:
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
Если вы работаете с числами больше этих значений (например, в финансовых расчётах или криптографии), то лучше использовать другой тип — BigInt (о нём — позже).
Есть ещё три особых числовых значения, с которыми вы точно столкнётесь:
Infinity — бесконечность. Получается, например, если делить на ноль:
console.log(10 / 0); // Infinity
-Infinity — минус бесконечность. То же самое, но с отрицательным числом:
console.log(-10 / 0); // -Infinity
NaN — это «Not a Number», то есть «не число». Возникает, когда результат операции нельзя выразить числом:
console.log(0 / 0); // NaN
console.log(Math.sqrt(-1)); // NaN
console.log(parseInt("abc")); // NaN
Тут есть одна ловушка: NaN не равен даже самому себе. Это кажется странным, но так и должно быть:
console.log(NaN === NaN); // false
Чтобы проверить, NaN ли перед вами, используйте функцию:
console.log(Number.isNaN(value)); // это правильный способ

Читайте также:
BigInt (большие целые числа)
BigInt покрывает диапазон, который не может охватить number. Чаще всего такие огромные числа используются в криптографии, и иногда это могут быть идентификаторы в базах данных.
Такое число пишется почти как обычное, только с буквой n на конце:
let bigNumber = 123456789012345678901234567890n;
console.log(bigNumber); // 123456789012345678901234567890n
С BigInt можно делать всё то же, что и с обычными числами: складывать, вычитать, умножать, делить, делить с остатком:
let a = 7n;
let b = 3n;
console.log(a + b); // 10n
Но нельзя смешивать BigInt и обычный number в одной операции. Такой код вызовет ошибку:
let num = 10;
let big = 20n;
console.log(num + big); // TypeError: нельзя складывать number и BigInt
Если очень нужно, одно из чисел можно преобразовать:
BigInt(10) + 20n; // 30n
Ещё один момент: при делении BigInt отбрасывает дробную часть. Результат всегда будет целым:
console.log(5n / 2n); // 2n, а не 2.5
Boolean (булев тип, логический)
Логический тип данных в JavaScript называется boolean. У него всего два значения: true (истина) и false (ложь). Звучит просто — и это действительно так. Булевы значения лежат в основе всей логики в коде: они используются в условиях, проверках, циклах и функциях.
Вот простой пример:
let isRaining = true;
if (isRaining) {
console.log("Возьми зонт!");
} else {
console.log("Можно идти без зонта.");
}
Переменная isRaining содержит булево значение. Условие в if проверяет, истинно ли оно, — и от этого зависит, какой код выполнится.
В JavaScript не обязательно писать true или false вручную. Во многих случаях язык сам решает, каким считать значение — истинным или ложным. Это называется неявное приведение к логическому типу.
Например, условие if (value) работает даже если value — это число, строка или объект. JavaScript попробует «перевести» это значение в true или false и уже потом примет решение.
if ("Привет") {
console.log("Это выполнится");
}
if (0) {
console.log("А это -- нет");
}
В первом случае строка "Привет" считается истинной, потому что она не пустая. Во втором — 0 считается ложным значением, поэтому блок if не срабатывает. Таких правил немного, и они всегда одинаковые.
Что считается false:
- 0;
- пустая строка "";
- null;
- undefined;
- NaN;
- false.
Всё остальное — true. Даже строка "0" или "false" (это всё равно true, потому что строка не пуста).
К true также относятся:
- массивы [];
- объекты {};
- Infinity и -Infinity.
Проверить, как значение ведёт себя в логике, можно через функцию Boolean():
Boolean(""); // false
Boolean("Привет"); // true
Boolean(0); // false
Boolean(42); // true
Тип boolean управляет всей логикой: что показать пользователю, когда что-то выполнять, на что реагировать. Чем раньше вы к нему привыкнете, тем легче станет читать и писать код.
Значение undefined («неопределённый»)
Примитив undefined означает, что переменная уже существует, но её значение пока не определено. То есть переменная есть, а данных в ней нет.
Такое часто случается, если переменную объявили, но забыли присвоить ей значение:
let name;
console.log(name); // undefined
Переменная name есть, но мы не задали ей значение — поэтому JavaScript возвращает undefined.
Такое значение может появиться и в других случаях. Например, если функция ничего не возвращает:
function sayHello() {
console.log("Привет!");
}
console.log(sayHello()); // undefined
Функция sayHello что-то делает, но не возвращает результат — и поэтому по умолчанию возвращается undefined.
Или если мы пытаемся обратиться к свойству объекта, которого нет:
let user = {};
console.log(user.age); // undefined -- такого свойства нет
Проверить, действительно ли значение undefined, можно через строгое сравнение:
let value;
if (value === undefined) {
console.log("Переменная не определена!");
}
Чтобы undefined не появлялся случайно, очень желательно:
- сразу присваивать значения при создании переменных;
- проверять, есть ли нужное свойство у объекта, перед использованием.
Значение null (пустая переменная)
В JavaScript есть особый тип данных — null. Он про то, что значения нет и это сделано специально. То есть вы как бы говорите: «Сейчас здесь ничего нет, но это нормально».
Чаще всего null используют, когда нужно явно указать, что переменная пуста:
let user = null; // данных пока нет
Или, например, в объекте:
let profile = {
name: null, // имя пока не задано
age: 25
};
Это не то же самое, что undefined. Разница в намерении: null — это явное указание на отсутствие значения. А undefined — это про то, что переменной не присвоено никакого значения. Это неявное отсутствие значения.
let a = null; // явно сказали: пусто
let b; // переменная есть, но без значения
console.log(a === b); // false -- это разные вещи
Проверить, null ли у переменной, можно с помощью строгого сравнения:
let data = null;
if (data === null) {
console.log("Значение пустое!");
}
Symbol (уникальный идентификатор)
Иногда в коде нужно добавить к объекту какое-то служебное свойство, которое не должно случайно пересечься с другими. Например, если вы используете чужой объект — из библиотеки или API — и хотите добавить к нему что-то своё, но не рисковать, что ваше свойство затрёт уже существующее. В таких случаях и помогает Symbol.
Символ — это уникальное значение, которое можно использовать как ключ в объекте. Даже если вы создадите два символа с одинаковыми описаниями, они всё равно будут разными:
let a = Symbol("id");
let b = Symbol("id");
console.log(a === b); // false -- это два разных символа
То есть Symbol гарантирует, что ключ, созданный с его помощью, не повторится ни случайно, ни по ошибке.
Это удобно, если вы, например, пишете модуль, который добавляет дополнительную информацию в объект, но не хотите мешать чужим свойствам:
const privateKey = Symbol("private");
let user = {
name: "Лена",
[privateKey]: "секретный токен"
};
console.log(user[privateKey]); // "секретный токен"
Символ можно использовать только как ключ, и он не появится при обычном переборе объекта — это тоже защита от случайного вмешательства.
Ещё есть так называемые глобальные символы. Их создают через Symbol.for("имя"). Если вызвать Symbol.for() с одним и тем же именем в разных частях программы, вернётся один и тот же символ:
let global1 = Symbol.for("shared");
let global2 = Symbol.for("shared");
console.log(global1 === global2); // true
Это помогает, если нужно использовать один и тот же уникальный ключ в нескольких местах, например при настройке общего кэша или хранения состояния между модулями.
Ссылочный тип данных — object
Объект — это особый тип данных в JavaScript, который используется для хранения нескольких значений внутри одной переменной. Например, имя пользователя, его возраст и почту можно объединить вот так:
let user = {
name: "Катя",
age: 25,
email: "katya@example.com"
};
Объекты — это основа большинства структур в JavaScript. К ним относятся не только обычные объекты, но и массивы, функции, даты и многое другое. Всё это — ссылочные типы.
Переменная хранит не сам объект целиком, а только ссылку на него — как ярлык или указатель. Если присвоить объект другой переменной, копируется тоже не сам объект, а ссылка на него:
let obj1 = { name: "Вася" };
let obj2 = obj1;
obj2.name = "Ася";
console.log(obj1.name); // "Ася"
В этом примере obj1 и obj2 указывают на один и тот же объект в памяти. Изменение через obj2 автоматически видно и через obj1, потому что это одна и та же сущность, просто с двумя именами.
Работать с объектами можно по-разному — добавлять и удалять свойства, перебирать их, а также вкладывать одни объекты в другие.
Как узнать, какой тип у переменной
В JavaScript есть специальный оператор typeof, который позволяет узнать, к какому типу относится значение. Он возвращает результат в виде строки.
Примеры:
typeof 10; // "number"
typeof "Привет"; // "string"
typeof undefined; // "undefined"
typeof {}; // "object"
typeof function() {}; // "function"
Обратите внимание на последний пример. Хотя функция — это объект, оператор typeof специально выделяет её в отдельный тип "function". Это сделано намеренно, чтобы было проще отличать функции от других объектов. Ведь функции в JavaScript могут вызываться (()) и имеют особые свойства, такие как call и apply. Поэтому typeof был специально адаптирован, чтобы выделять функции.
Оператор typeof можно писать со скобками и без — разницы нет:
typeof 15; // "number"
typeof(15); // "number"
Но скобки могут пригодиться, если вы определяете тип целого выражения, особенно если оно выглядит неоднозначно:
typeof 38 + " попугаев"; // "number попугаев"
typeof (38 + " попугаев"); // "string"
В первом случае JavaScript сначала вычисляет typeof 38, получая строку "number", и потом прибавляет к ней " попугаев". Во втором — сначала складываются число и строка (что даёт строку), а потом уже typeof возвращает "string".
Так что, если вы хотите точно проверить тип результата выражения, используйте скобки — так безопаснее и понятнее.
Неочевидности typeof: NaN и null
Иногда typeof может вернуть результат, который выглядит странно. Один из таких случаев — NaN. Это специальное значение, которое означает «не число», но при этом:
console.log(typeof NaN); // "number"
Да, NaN — это технически число. Просто «неправильное». Например, оно может появиться в результате некорректной арифметики:
let result = 0 / 0; // NaN
Проверить, является ли значение именно NaN, можно несколькими способами — но не все из них надёжны.
Вот пример:
let value1 = NaN;
let value2 = 42;
let value3 = "hello";
// Плохой способ
console.log(isNaN(value1)); // true
console.log(isNaN(value2)); // false
console.log(isNaN(value3)); // true (!) -- хотя это строка, не NaN
// Тоже не подойдёт:
console.log(value1 === NaN); // false -- NaN не равен даже самому себе
// Правильный способ:
console.log(Number.isNaN(value1)); // true
console.log(Number.isNaN(value2)); // false
console.log(Number.isNaN(value3)); // false
Вывод: используйте Number.isNaN() — это единственный способ, который выдает корректный результат.
Если вы попробуете проверить typeof null, то получите:
console.log(typeof null); // "object"
Это, мягко говоря, неожиданно. Значение null — это не объект, а отдельное специальное значение, которое означает «здесь точно ничего нет».
Почему тогда typeof null возвращает "object"? Это баг, который появился ещё в самой первой версии JavaScript. Его не исправляют до сих пор, потому что слишком много кода во всём мире полагается на это поведение.
Так что просто запомните: typeof null всегда будет "object", но сам null объектом не является.
Если нужно проверить значение именно на null, используйте строгое сравнение:
if (value === null) {
// Да, это null
}
Такие особенности — часть «характера» JavaScript. Главное — знать, где подвох, и использовать правильные способы проверки.
Как JavaScript сам меняет типы и как этим управлять
В JavaScript всё гибко — даже слишком. Значения одного типа могут неожиданно превратиться в другой. Это называется приведение типов. Иногда оно происходит автоматически, иногда — только если вы сами этого хотите.
Например, пользователь ввёл число в форму. На экране видно «10», но в коде это не число, а строка:
const a = "10";
const b = "5";
console.log(a + b); // "105"
JavaScript увидел строки и решил: раз плюс, то, наверное, нужно их склеить. И получил строку "105" вместо ожидаемой суммы.
Чтобы всё сработало правильно, строки нужно явно превратить в числа:
const sum = Number(a) + Number(b);
console.log(sum); // 15
Это и есть явное преобразование — когда вы точно говорите: «Преобразуй вот это значение в число, строку или логическое выражение».
String(123); // "123"
Number("123"); // 123
Boolean(0); // false
А вот неявное преобразование происходит, когда JavaScript сам решает, что и к чему надо привести. Например:
console.log(5 + "5"); // "55" -- число стало строкой
console.log("10" - 5); // 5 -- строка стала числом
console.log(true + false); // 1 -- true → 1, false → 0
Даже такие сравнения работают, хотя выглядят странно:
null == undefined; // true
JavaScript решил, что null и undefined — примерно одно и то же, и вернул true. Именно из-за таких особенностей часто возникают ошибки.
Чтобы избежать путаницы, можно использовать строгое сравнение (===). Оно не приводит типы и возвращает false, если типы не совпадают:
"5" == 5; // true
"5" === 5; // false
Есть всего три типа, к которым можно привести значение:
- к строке — String(value);
- к числу — Number(value);
- к логическому значению — Boolean(value).
Примитивные типы (числа, строки и так далее) приводятся по простым правилам. Но если вы попытаетесь преобразовать объект, JavaScript сначала попытается превратить его в примитив и уже потом — в нужный тип. Это работает по сложным внутренним алгоритмам (valueOf, toString и так далее), и на начальном этапе их можно просто избегать.
Преобразование в строку (String)
Чтобы сделать число, null, undefined, true или false строкой, используют функцию String().
String(123); // '123'
String(null); // 'null'
String(true); // 'true'
Есть и неявный способ — прибавить к значению пустую строку. Это сработает почти так же:
123 + ""; // "123"
false + ""; // "false"
Но с Symbol так не сработает — его можно преобразовать только явно.
String(Symbol('test')); // 'Symbol(test)'
'' + Symbol('test'); // Ошибка TypeError
Преобразование в Boolean
Чтобы получить логическое значение (true или false), используйте Boolean():
Boolean(2); // true
Boolean(0); // false
Boolean(""); // false
Boolean("hi"); // true
Неявное преобразование происходит в логических выражениях — например, в if или при использовании операторов !, ||, &&:
if (2) { ... } // 2 → true
!!2; // true
2 || "hello"; // 2 (первый истинный)
"hi" && 123; // 123 (последний истинный)
Мы уже писали выше, что значения вроде 0, "", null, undefined и NaN считаются ложными (false). Всё остальное — истинными (true).
Преобразование в Number
Чтобы явно превратить значение в число, используйте Number():
Number("123"); // 123
Number(" 12 "); // 12
Number("12s"); // NaN
Number(null); // 0
Number(true); // 1
Number(false); // 0
Number(undefined); // NaN
Неявное преобразование в число происходит при использовании операторов +, -, *, /, >, <, != и других:
+"123"; // 123 (унарный +)
4 > "5"; // true ("5" → 5)
5 / null; // Infinity (null → 0)
true | 0; // 1 (true → 1, 0 → 0)
Как строки становятся числами:
- пробелы, \n, \t в начале и в конце удаляются;
- если остаётся только число — преобразование успешно;
- если есть лишние символы — результатом будет значение NaN.
Number(" 42 "); // 42
Number("\n"); // 0
Number("42px"); // NaN
Особые случаи:
- null → 0,
- undefined → NaN,
- Symbol нельзя преобразовать в число.
Number(Symbol("test")); // Ошибка TypeError
+"Symbol()"; // Ошибка TypeError
Значение null не превращается в 0 при сравнении через ==. Это частая ловушка:
null == 0; // false
null == null; // true
null == undefined; // true
Преобразование объектов в примитивы
Когда объект нужно использовать как примитив — например, в арифметике или в строке, — JavaScript пытается преобразовать его. Это может быть преобразование к числу, строке или логическому значению.
Логическое преобразование
Всегда даёт true, даже для пустых объектов и массивов:
Boolean({}); // true
Boolean([]); // true
Число и строка
JavaScript использует специальные методы объекта:
- при преобразовании к числу сначала вызывается valueOf(), потом toString();
- при преобразовании к строке — наоборот, то есть сначала toString(), потом valueOf().
Если оба метода вернут объект, а не примитив, будет ошибка:
let obj = {
toString() { return {}; },
valueOf() { return {}; }
};
console.log(+obj); // TypeError
Особенности операторов
- + и == используют стандартное преобразование (обычно к числу, но у Date — к строке);
- -, *, / и другие арифметические операторы — всегда к числу.
Symbol.toPrimitive
С помощью специального метода Symbol.toPrimitive можно точно задать, как объект должен вести себя при преобразовании:
let user = {
[Symbol.toPrimitive](hint) {
if (hint === "string") return "Пользователь";
if (hint === "number") return 1;
return null;
}
};
console.log(String(user)); // "Пользователь"
console.log(+user); // 1
Интересные факты
Ноль в JavaScript имеет два представления — -0 и +0. В большинстве случаев это не имеет какого-то практического значения, за исключением деления на ноль:
42 / +0
Infinity
42 / -0
-Infinity
Практика: как работают типы данных
Попробуйте выполнить эти задания. Чтобы проверить себя, запустите код в консоли браузера (F12 → Вкладка "Console") на сайте вроде CodePen или JSFiddle или в Node.js.
Задание: определите тип каждой переменной
let a = 42;
let b = "Hello, world!";
let c = true;
let d = null;
let e = undefined;
let f = { name: "Alice" };
let g = [1, 2, 3];
let h = function() { return "Hi!"; };
console.log(typeof a); // ?
console.log(typeof b); // ?
console.log(typeof c); // ?
console.log(typeof d); // ?
console.log(typeof e); // ?
console.log(typeof f); // ?
console.log(typeof g); // ?
console.log(typeof h); // ?
Подумайте, что выведет typeof для каждой переменной, — и только потом запускайте. Обратите внимание на особые случаи, они тут есть.
Преобразование типов
Приведите строку к числу и наоборот, затем проверьте результат с помощью typeof:
let str = "123";
let num = 456;
// Преобразование строки в число
let strToNum = Number(str);
// Преобразование числа в строку
let numToStr = String(num);
console.log(typeof strToNum); // ?
console.log(typeof numToStr); // ?
Поиск ошибок в коде
В приведённом коде есть ошибки, связанные с неверным приведением типов. Исправьте код так, чтобы он работал правильно и выдавал ожидаемые результаты.
function calculateTotal(price, discount) {
return price - discount + " рублей";
}
let total = calculateTotal("100", 20);
console.log("Итоговая цена:", total); // Ожидаемый результат: "80 рублей", но что-то не так...
- Почему результат получается не числом, а строкой?
- Как правильно преобразовать строку `"100"` в число?
- Как исправить функцию, чтобы она корректно считала итоговую цену?
Неявное преобразование
Подумайте, что выведет консоль, а затем проверьте себя:
console.log("5" + 3); // ?
console.log("5" - 3); // ?
console.log("5" * "2"); // ?
console.log("5" / "2"); // ?
console.log(10 + true); // ?
console.log(10 + false);// ?
console.log(10 + null); // ?
console.log(10 + undefined); // ?
Операторы и типы данных
Заполните пропущенные значения:
console.log(typeof NaN); // ?
console.log(typeof null); // ?
console.log(typeof []); // ?
console.log(typeof {}); // ?
console.log(typeof function(){}); // ?
console.log([] + {}); // ?
console.log({} + []); // ?
console.log([] + 1); // ?
console.log({} + 1); // ?
Чуть сложнее
Если предыдущие задания показались вам простыми, подумайте над этими:
18 / "6"
!!"false" == !!"true"
'a' == ['a']
false == 'false'
"number" + 1 + 2
1 + 2 + "number"
[1] > null
"foo" + + "bar"
'true' == true
null == ''
{}+[]+{}+[2]
!+[]+[]+![]
[] + null + 1
0 || "0" && {}
false + true
[1,2,3] == [1,2,3]
new Date(0) - 0
new Date(0) + 0
Полезные материалы
- Типы и структуры данных JavaScript. Документация MDN.
- JavaScript Data Types
- Вы не знаете JS: Типы и грамматика
- История ошибки typeof null: The history of “typeof null”
- JavaScript-Equality-Table - наглядный пример того, как работает ==, === и if()
Больше интересного про код — в нашем телеграм-канале. Подписывайтесь!