JavaScript для тех, кто знает PHP или Python: перенос привычек
Асинхронность, this и передача объектов по ссылке ломают привычки бэкендера сильнее, чем синтаксис. Разбираем, где интуиция из PHP и Python подводит в JavaScript.

Вы умеете писать на PHP или Python и открыли JavaScript, потому что фронт, Node.js или просто скрипт в браузере. Синтаксис вы освоите за вечер: фигурные скобки, if, for, функции. Проблема не в синтаксисе. Проблема в том, что три вещи работают не так, как подсказывает опыт бэкендера: асинхронность по умолчанию, значение this и то, что почти всё, кроме примитивов, передаётся по ссылке. Именно на них уходит первая неделя недоумения. Разбираем их на конкретных примерах, а не пересказываем справочник по операторам.
Ориентируемся на современный JavaScript (ES2020 и новее) и Node.js 20.x — то, что вы встретите в большинстве проектов сегодня. Синтаксис вроде let, const, стрелочных функций и async/await считаем базой, а не экзотикой.
Переменные: три ключевых слова вместо одного
В PHP переменная — это $name, в Python — просто name. В JavaScript у объявления три варианта, и выбор влияет на поведение.
- const — ссылку нельзя переприсвоить. Используйте по умолчанию.
- let — переменная, которую вы будете менять. Счётчики, накопители.
- var — старый способ с областью видимости на всю функцию, а не на блок. В новом коде не используйте.
Ловушка: const запрещает переприсвоение, но не запрещает мутацию. Массив, объявленный через const, спокойно принимает push. Это не Python, где tuple действительно неизменяемый.
const items = [1, 2];
items.push(3); // работает, items === [1, 2, 3]
items = [4, 5]; // TypeError: Assignment to constant variableСравнение: почему == вас подставит
В PHP оператор == тоже приводит типы, и это уже приносило боль. В JavaScript коэффициент абсурда выше. 0 == "", 0 == "0", но "" != "0" — таблица приведений нетранзитивна.
Правило простое: всегда используйте === и !==. Они сравнивают без приведения типов, как is для примитивов в мышлении Python-разработчика (хотя механика другая). Оператор == оставьте для одного случая — проверки на null или undefined сразу: value == null истинно и для null, и для undefined.
Асинхронность — то, чего нет в базовом PHP
Здесь ломается интуиция сильнее всего. В PHP код выполняется сверху вниз: строка с запросом к базе блокирует выполнение, пока не вернётся результат. В Python по умолчанию так же, пока вы не возьмёте asyncio.
В JavaScript многое асинхронно по умолчанию. Сетевой запрос, чтение файла в Node, таймер — всё возвращает управление немедленно, а результат приходит позже. Попытка читать это как синхронный код даёт классическую ошибку новичка:
// НЕПРАВИЛЬНО: fetch не блокирует, data будет undefined
function getUser() {
let data;
fetch('https://api.example.com/user')
.then(response => response.json())
.then(json => { data = json; });
return data; // вернётся раньше, чем придёт ответ
}Правильный способ в современном коде — async/await. Он читается почти как синхронный, но не блокирует поток:
// ПРАВИЛЬНО: await ждёт результат, не блокируя остальной рантайм
async function getUser() {
const response = await fetch('https://api.example.com/user');
const data = await response.json();
return data;
}
// Вызов тоже требует await или .then
const user = await getUser();Ключевое отличие от Python-мышления: функция, помеченная async, всегда возвращает Promise. Даже если внутри вы написали return 5, снаружи придёт не 5, а обещание, которое разрешится в 5. Забыли await — получите объект Promise вместо значения, и это самый частый баг первых недель.
Если вы пришли из синхронного PHP, запомните одно: в JavaScript результата сетевого или файлового вызова почти никогда нет в той же строке, где вы его запросили. Он приходит позже, и язык дал вам await, чтобы дождаться его без блокировки.this — не то, что вы думаете
В PHP внутри метода класса $this предсказуемо указывает на объект. В Python вы явно принимаете self первым аргументом. В JavaScript значение this определяется не тем, где функция объявлена, а тем, как она вызвана.
const account = {
balance: 100,
showBalance() {
console.log(this.balance);
}
};
account.showBalance(); // 100 — this это account
const fn = account.showBalance;
fn(); // undefined — this потерянСпасение — стрелочные функции: они не создают собственный this, а берут его из окружающего кода. Для колбэков и обработчиков используйте именно их. Для методов объекта, где this должен указывать на сам объект, оставляйте обычные функции.
Передача по ссылке: где Python-разработчику проще
Тут интуиция из Python помогает, а из PHP — мешает. Примитивы (число, строка, булево) передаются по значению. Объекты и массивы — по ссылке.
function addTax(order) {
order.total = order.total * 1.2; // мутирует исходный объект
}
const cart = { total: 100 };
addTax(cart);
console.log(cart.total); // 120 — оригинал изменёнЧтобы не портить исходный объект, делайте копию через spread-оператор: const copy = { ...order }. Но помните — это поверхностная копия. Вложенные объекты останутся общими ссылками.
Сводная таблица привычек
| Вопрос | PHP | Python | JavaScript |
|---|---|---|---|
| Строгое сравнение | === | == (по значению) | === |
| Отсутствие значения | null | None | null и undefined |
| Асинхронность по умолчанию | нет | нет (нужен asyncio) | да |
| Конкатенация строк | . | + | + или шаблоны `${x}` |
| Ложные значения в условии | 0, "", null, [] | 0, "", None, [] | 0, "", null, undefined, NaN (но не []) |
Последняя строка — отдельная засада. В Python и PHP пустой массив ложный. В JavaScript пустой массив [] и пустой объект {} — истинны в условии. Проверять массив на пустоту нужно через arr.length === 0, а не if (!arr).
null и undefined — их два
В PHP и Python отсутствие значения — одна сущность. В JavaScript их две. undefined — переменная объявлена, но значение не присвоено, или свойство объекта не существует. null — вы сами явно сказали «здесь пусто». На практике: проверяйте оба сразу через value == null либо используйте оператор ?? для значения по умолчанию:
const name = user.name ?? 'Гость';
// если user.name это null или undefined — вернётся 'Гость'
// но если user.name === '' или 0 — вернётся именно ониОтличие от ||: старый способ user.name || 'Гость' подставит 'Гость' и для пустой строки, и для нуля, что часто не то, что вам нужно.
Что делать дальше
Соберите привычку из трёх пунктов и первый месяц держите её сознательно: всегда ===, всегда await для асинхронных вызовов, стрелочные функции для колбэков. Дальше берите линтер ESLint с конфигом, который сам подсветит ==, потерянный await и необъявленные переменные — это быстрее, чем ловить те же ошибки в рантайме. Следующая большая тема после базы — обработка ошибок в асинхронном коде через try/catch вокруг await: она работает не так очевидно, как в синхронном PHP, и заслуживает отдельного разбора.
Дефектный акт по фото: Осмотр по фотографиям: классификация дефектов, ссылки на нормы, требования к устранению. Готовый акт в Word.
Спросить за 80 ₽Источники: JavaScript — MDN Web Docs, Equality comparisons and sameness — MDN
Частые вопросы
У меня старый проект без async/await, там сплошные колбэки и .then. Мой код с await туда впишется?
Почему у меня в консоли выводится Promise { <pending> } вместо данных?
Что использовать в браузере, а что в Node.js — есть разница в этих основах?
Нужно ли мне учить TypeScript сразу или сначала чистый JavaScript?
Опасно ли, что const позволяет менять массив — я привык, что константа неизменна?
В каких версиях появились оператор ?? и spread — сработают ли они у меня?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.