История JavaScript и TypeScript
Зачем это нужно
История языка — не музейная экскурсия. Это объяснение, почему код ведёт себя странно.
Вот пять фактов, каждый из которых сегодня отнимает у новичка час:
console.log(typeof null); // 'object'
console.log([] == false); // true
console.log(0.1 + 0.2); // 0.30000000000000004
console.log([10, 1, 2].sort()); // [ 1, 10, 2 ]
console.log(typeof NaN); // 'number'
Всё это — живой запуск на Node.js 24, самой свежей версии. Ни один из этих ответов не является «правильным» в человеческом смысле. Каждый — след конкретного решения, принятого в конкретный год конкретным человеком, у которого не было времени подумать.
Понимая историю, вы:
- перестаёте искать логику там, где её нет, и просто помните исключение;
- понимаете, почему в интернете половина примеров написана совсем не так, как учат сейчас;
- знаете, что можно использовать, а что нельзя, — и не по чужому совету, а сами;
- отличаете «язык такой» от «я что-то делаю не так».
Последнее особенно важно на первом курсе. Половина мучений начинающего — это попытка найти смысл там, где на самом деле лежит совместимость с браузером 1997 года.
- Зачем это нужно
- Десять дней в мае 1995-го
- Почему «JavaScript», если это не Java
- Война браузеров и рождение стандарта
- ECMAScript: почему у языка два имени
- ES4: версия, которой не было
- 2008: V8 и почему JavaScript вдруг стал быстрым
- 2009: Node.js — язык вышел из браузера
- npm и история с одиннадцатью строками
- 2015: ES6 — та самая граница
- Что было после: версии по годам
- Как принимают новое: TC39 и стадии
- 2012: зачем понадобился TypeScript
- Андерс Хейлсберг: один человек и четыре языка
- 2016: strictNullChecks — переломная версия
- Где TypeScript заканчивается: типы стираются
- Deno и Bun: попытки переделать Node
- Почему в языке столько странного: «не ломать веб»
- Почему в блокчейне именно JavaScript и TypeScript
- Что дальше: типы в самом JavaScript
- Типичные заблуждения
- Тренажёр: даты и имена вслепую
- Даты, которые стоит помнить
- Что должен уметь
- Куда дальше: проверенные ресурсы
Десять дней в мае 1995-го
Компания Netscape делала браузер Navigator и в 1995 году занимала почти весь рынок. Страницы тогда были полностью мёртвыми: текст, картинки, ссылки. Netscape решил, что странице нужен свой язык — чтобы проверить форму до отправки на сервер и показать что-нибудь в ответ на клик.
Задачу поручили Брендану Айку, который пришёл в компанию в апреле. Условия были такие:
- язык должен появиться к следующей бете браузера, то есть примерно за две недели;
- он должен «выглядеть как Java», потому что Java в 1995 году была на пике моды;
- он должен быть простым настолько, чтобы на нём писали дизайнеры, а не программисты.
Первая работающая версия была написана за десять дней. Это не легенда и не преувеличение — это официальная часть истории языка, о которой сам Айк рассказывал многократно.
Что попало в язык из этих десяти дней:
| Откуда взято | Что именно |
|---|---|
| Scheme | функции как обычные значения, замыкания |
| Self | прототипы вместо классов |
| Java | внешний вид: фигурные скобки, for, if, точка с запятой |
| Спешка | typeof null, автоматическое приведение типов, var |
Первое имя языка было Mocha, второе — LiveScript, и под этим именем он вышел в сентябре 1995-го.
Почему «JavaScript», если это не Java
В декабре 1995 года Netscape и Sun Microsystems выпустили совместное заявление, и LiveScript был переименован в JavaScript.
Причина была чисто маркетинговая. Java принадлежала Sun и переживала бум; Netscape договорился с Sun о партнёрстве, и общее имя должно было помочь обоим. Технического родства между языками нет и не было: у них разная модель типов, разная модель объектов, разная модель памяти и разная область применения.
Знаменитая формулировка, которая полностью описывает ситуацию: Java и JavaScript соотносятся примерно как «автомобиль» и «ковёр» — общее слово в названии есть, общего смысла нет.
Последствия этого решения тянутся до сих пор:
- вакансии до сих пор путают, а начинающие ищут «уроки Java», попадая не туда;
- имя
JavaScriptоставалось торговой маркой Sun (позже Oracle), из-за чего стандарт назвали иначе — об этом ниже; - и до сих пор приходится объяснять на каждом собеседовании, что это разные языки.
В коде на JavaScript действительно встречаются слова из Java, которые ничего не делают: class, extends, super, import, enum, char, int, byte, goto и ещё десяток. Часть из них зарезервировали «на будущее» в 1995 году просто потому, что они были в Java.
Некоторые так и не пригодились: int, char, byte, goto в языке нет и не будет, но использовать их как имена переменных нельзя до сих пор. Попробуйте написать const int = 5 в строгом режиме — получите синтаксическую ошибку из-за решения тридцатилетней давности.
Война браузеров и рождение стандарта
Успех JavaScript в Navigator означал, что Microsoft обязана ответить. Ответ появился в 1996 году вместе с Internet Explorer 3: язык JScript — восстановленная по поведению копия JavaScript, потому что никакой спецификации не существовало.
Дальше началось то, что позже назвали войной браузеров. Обе компании добавляли в свои версии языка что хотели, страницы работали в одном браузере и ломались в другом, а разработчики писали код в два экземпляра. Отсюда родился жанр, который жил ещё пятнадцать лет:
// код 1998 года: догадаться, где мы находимся
if (document.all) {
// Internet Explorer
} else if (document.layers) {
// Netscape Navigator
}
Проверять таким способом «какой у нас браузер» и сегодня считается плохим тоном, но именно здесь эта привычка началась.
В ноябре 1996 года Netscape передал язык в организацию по стандартизации Ecma International. Идея была простая: пусть будет один документ, по которому все делают одинаково.
ECMAScript: почему у языка два имени
Первая редакция стандарта — ECMA-262, июнь 1997 года. Языку в стандарте дали имя ECMAScript, и причина этому чисто юридическая: имя JavaScript было торговой маркой Sun, и назвать так открытый стандарт было нельзя.
Так и живём с тех пор:
- ECMAScript — название стандарта, документа;
- JavaScript — название языка в обиходе и в вакансиях;
- ES6, ES2015, ES2020 — версии стандарта.
Сам Брендан Айк называл имя «ECMAScript» неудачным, сравнивая его с кожным заболеванием. Тем не менее прижилось.
Ранние редакции:
| Версия | Год | Что дала |
|---|---|---|
| ES1 | 1997 | первая запись того, что уже работало |
| ES2 | 1998 | только приведение к международному стандарту ISO, без изменений языка |
| ES3 | 1999 | регулярные выражения, try/catch, do..while, строгое сравнение |
ES3 оказалась опорной точкой на целое десятилетие: до 2009 года ничего нового в стандарте не появлялось.
ES4: версия, которой не было
С 2000 года комитет работал над четвёртой редакцией, и замысел был огромный: классы, модули, пространства имён и статическая типизация прямо в языке. По сути — то, чем позже стал TypeScript, но встроенное.
Проект не вышел. К 2008 году комитет раскололся: одна часть участников считала, что язык нужно менять радикально, другая — что такой скачок сломает существующие сайты и никто не станет его внедрять. Договориться не удалось, и работу закрыли.
Последствия оказались долгими:
- номер 4 пропущен: после ES3 идёт ES5, версии ES4 в природе не существует;
- восемь лет застоя: 1999–2009 в языке не менялось ничего;
- урок комитету: с тех пор изменения принимают маленькими порциями и по одной штуке, а не пакетом;
- типы в язык так и не попали — и именно этот вакуум через четыре года заняла отдельная надстройка.
ES5 вышла в декабре 2009 года и была сознательно скромной: строгий режим 'use strict', встроенный объект JSON, Object.defineProperty и методы массивов, без которых сегодня не пишут ни строки, — map, filter, reduce, forEach.
2008: V8 и почему JavaScript вдруг стал быстрым
До 2008 года JavaScript был медленным, и это считалось свойством языка. Программу разбирали и выполняли по строчке — примерно так же, как работает простой интерпретатор.
В сентябре 2008 года Google выпустил браузер Chrome, а вместе с ним движок V8. Главная идея V8 — не интерпретировать, а компилировать код в машинные инструкции прямо во время работы. Этот приём называют JIT-компиляцией: движок смотрит, какие функции вызываются часто, и переводит именно их в машинный код, попутно догадываясь о типах по фактическим значениям.
Разница в скорости оказалась не в проценты, а в десятки раз. Остальные движки ответили тем же в течение года.
Почему это ключевое событие в истории языка: до V8 писать на JavaScript что-то серьёзнее проверки формы было бессмысленно. После V8 стало возможно всё остальное — и первым же следствием стало то, что язык вышел за пределы браузера.
У JIT-компиляции есть обратная сторона, о которой полезно знать заранее: движок ускоряет код, пока тот предсказуем. Если функция всегда получала числа, а потом ей передали строку, движок выбрасывает оптимизированную версию и начинает заново.
Отсюда практическое правило, которое звучит неожиданно для языка без типов: держите тип значения в переменной постоянным. TypeScript, помимо ловли ошибок, невольно помогает именно этим — код, который проходит проверку типов, обычно оказывается и предсказуемым для движка.
2009: Node.js — язык вышел из браузера
В 2009 году Райан Дал взял движок V8, добавил к нему доступ к файлам, сети и процессам и получил Node.js — способ запускать JavaScript вне браузера.
Что это изменило:
- один язык стал годиться и для страницы, и для сервера;
- появились инструменты командной строки на JavaScript — сборщики, линтеры, генераторы;
- у языка появилась стандартная библиотека, которой у него никогда не было:
fsдля файлов,httpдля сети,processдля окружения.
Вторая идея Node.js важнее первой. Дал строил его вокруг неблокирующего ввода-вывода: пока запрос к диску или к сети выполняется, поток не ждёт, а занимается другими задачами. Для сервера, обслуживающего тысячи одновременных соединений, это оказалось выигрышной моделью — и вся асинхронность JavaScript, которую сегодня записывают через async/await, выросла именно отсюда.
Для нашего курса Node.js — это то, в чём запускается весь код блокчейн-трека: SDK, скрипты, тесты.
npm и история с одиннадцатью строками
Вместе с Node.js в 2010 году появился npm — хранилище пакетов и программа для их установки. Идея очевидная: не писать в сотый раз то, что уже написано.
npm вырос в самое большое хранилище кода в мире. И вместе с размером пришла проблема, которую лучше всего описывает один случай.
В марте 2016 года автор пакета left-pad поссорился с площадкой и удалил свой пакет. Пакет состоял из одиннадцати строк и добавлял пробелы в начало строки до нужной длины. В тот же час перестали собираться тысячи проектов по всему миру, включая React и Babel: left-pad оказался зависимостью зависимости зависимости.
Выводы, которые из этого сделала индустрия и которые касаются вас с первого же проекта:
- каждая зависимость — это доверие: вы пускаете чужой код в свою программу, и код автора зависимости вашей зависимости тоже;
- держите файл
package-lock.jsonв репозитории — он фиксирует точные версии всего дерева; - не ставьте пакет ради одной функции, которую можно написать за пять минут;
- смотрите на дату последнего обновления и число сопровождающих до установки, а не после.
Особенно это важно в блокчейне: пакет, попавший в проект, работает рядом с приватными ключами.
2015: ES6 — та самая граница
В июне 2015 года вышла ES6, она же ES2015. Это самая большая версия за всю историю языка и настоящая граница между старым и новым кодом.
Что появилось разом:
| Появилось | Что заменило |
|---|---|
let и const | var со всеми его странностями |
| стрелочные функции | function плюс ручное сохранение this |
class | ручную работу с прототипами |
модули import/export | подключение файлов тегами и глобальные переменные |
| шаблонные строки | склейку через + |
| деструктуризация | десять строк присваиваний |
Promise | вложенные коллбэки |
Map, Set | объект и массив в неподходящей роли |
значения по умолчанию, ... | проверки arguments руками |
Практический смысл этой даты для вас конкретный: любой пример из интернета, где встречается var, написан до 2015 года. Он не обязательно неправильный, но точно устаревший, и рядом с ним наверняка есть другие устаревшие приёмы.
Вот наглядное подтверждение того, что заменили let и const:
var x = 1;
{ var x = 2; }
console.log(x); // 2 — блок ничего не ограничил
let y = 1;
{ let y = 2; }
console.log(y); // 1 — блок работает как ожидается
Живой запуск даёт 2 и 1. var не видит фигурных скобок, и это была причина огромного числа ошибок до 2015 года.
Что было после: версии по годам
После ES6 комитет перешёл на годовой цикл: небольшой набор готовых изменений выпускают раз в год, и версия называется по году.
| Версия | Заметное |
|---|---|
| ES2016 | оператор **, метод includes |
| ES2017 | async/await — асинхронный код стал похож на обычный |
| ES2018 | ... для объектов, асинхронный for await |
| ES2019 | flat, trimStart, catch без параметра |
| ES2020 | ?., ??, BigInt — большие целые числа |
| ES2021 | replaceAll, логические присваивания |
| ES2022 | поля класса с #, at(), await на верхнем уровне модуля |
| ES2023 и дальше | методы массивов без изменения оригинала: toSorted, toReversed |
Учить это по годам не нужно и вредно. Полезно другое: помнить, что язык продолжает меняться, и любой ответ на форуме, помеченный 2016 годом, может оказаться описанием приёма, который давно заменён встроенной возможностью.
Хороший пример — ?. и ?? из ES2020. До них безопасное чтение вложенного поля выглядело так:
var address = tx && tx.recipient && tx.recipient.address ? tx.recipient.address : 'нет';
А теперь так:
const address = tx?.recipient?.address ?? 'нет';
Одна строка вместо одной длинной и хрупкой. Именно поэтому старые примеры выглядят тяжело.
Как принимают новое: TC39 и стадии
За развитие языка отвечает комитет TC39 внутри Ecma. В нём представлены компании, которые делают браузеры и движки: Google, Apple, Mozilla, Microsoft и другие, плюс независимые участники.
Любое изменение проходит пять стадий:
| Стадия | Что означает |
|---|---|
| 0 | идея записана |
| 1 | задача признана осмысленной, ищут решение |
| 2 | есть черновик синтаксиса |
| 3 | описание готово, ждут реализации в движках и отзывов |
| 4 | принято, входит в ближайшую версию стандарта |
Практический смысл этой таблицы: увидев в статье «новую возможность JavaScript», первым делом посмотрите стадию. Всё, что ниже 3, может измениться или исчезнуть, и строить на этом проект не стоит.
Главный принцип, которым комитет руководствуется во всех спорах, звучит так: не ломать веб. Страница, написанная в 1998 году, обязана открываться в браузере 2026 года. Отсюда следует всё, что в языке кажется нелогичным, — этому посвящён отдельный раздел ниже.
2012: зачем понадобился TypeScript
К началу 2010-х выяснилось неприятное: на JavaScript начали писать большие программы, а язык к этому не был приспособлен.
Конкретные боли, из которых вырос TypeScript:
- опечатка в имени поля молча создаёт новое поле — программа работает, результат неверный;
- непонятно, что принимает функция: чтобы узнать, нужно прочитать её целиком, а часто и всё, что она вызывает;
- переименование поля в редакторе невозможно: инструмент не знает, где какое поле, потому что типов нет;
- ошибка обнаруживается у пользователя, а не при написании.
Microsoft выпустила первую публичную версию TypeScript в октябре 2012 года. Замысел был принципиально другой, чем у прошлых попыток: не новый язык, а надстройка. Любой корректный файл на JavaScript — это корректный файл на TypeScript. Типы дописываются сверху, а на выходе получается обычный JavaScript, который выполняется где угодно.
Именно это решение и обеспечило успех там, где провалились предшественники: переходить можно было по одному файлу, а не переписывать проект целиком.
Ключевые версии:
| Версия | Год | Что дала |
|---|---|---|
| 0.8 | 2012 | первая публичная |
| 1.0 | 2014 | признание стабильной |
| 2.0 | 2016 | strictNullChecks — переломная возможность |
| 5.x | 2023 | стандартные декораторы, ускорение |
| 6.x | к 2026 | версия, которая стоит в этом курсе |
Андерс Хейлсберг: один человек и четыре языка
У TypeScript есть главный архитектор — Андерс Хейлсберг. Его биография объясняет, почему язык получился именно таким.
| Годы | Что сделал |
|---|---|
| 1980-е | Turbo Pascal — компилятор, который компилировал быстрее, чем конкуренты успевали запуститься |
| 1990-е | Delphi — среда, на которой написана огромная часть корпоративного софта |
| 2000-е | C# — главный язык платформы .NET |
| 2012 и далее | TypeScript |
Через все четыре проекта проходит одна и та же идея: инструмент должен помогать во время написания кода, а не после. Turbo Pascal был известен мгновенной компиляцией, Delphi — подсказками в редакторе, C# — строгостью, которая ловит ошибки заранее.
TypeScript построен на том же: главная его ценность не в «типах» как таковых, а в том, что редактор наконец знает про ваш код достаточно, чтобы подсказывать, переименовывать и находить ошибки, пока вы печатаете.
Кстати, из этой же биографии становится понятно, почему записи в TypeScript так похожи на C#: public readonly, private, interface, implements, abstract — почти дословно.
2016: strictNullChecks — переломная версия
Первые версии TypeScript ловили далеко не всё. Главная дыра была в том, что null и undefined подходили под любой тип: строка могла оказаться null, число — undefined, и компилятор не возражал.
А это ровно та ошибка, которая чаще всего валит настоящие программы:
TypeError: Cannot read properties of undefined (reading 'address')
В TypeScript 2.0 появился флаг strictNullChecks. С ним string означает именно строку, а «строка или ничего» приходится писать явно — string | null, — и компилятор требует проверку перед использованием.
function show(name: string | null) {
console.log(name.length); // ошибка: name может быть null
if (name) console.log(name.length); // а так можно
}
Именно с этой версии TypeScript начали воспринимать всерьёз: он стал ловить ту самую ошибку, ради которой всё затевалось. Сегодня strictNullChecks входит в общий флаг strict, и проект без него считается настроенным небрежно.
Автор идеи «типа, который может быть пустым» — Тони Хоар, придумавший null ещё в 1965 году, — назвал своё изобретение ошибкой на миллиард долларов. strictNullChecks — это способ жить с последствиями.
Где TypeScript заканчивается: типы стираются
Самое важное, что нужно понять про TypeScript, — где проходит граница его действия.
Возьмём файл с типами и посмотрим, во что его превращает компилятор. Это настоящий вывод tsc --target es2022:
interface Signer { sign(d: string): string; }
type Level = 'low' | 'high';
class Tx implements Signer {
static count = 0;
#secret = 'k';
constructor(public readonly id: string, private amount: number) { Tx.count++; }
get fee(): number { return this.amount * 0.001; }
sign(d: string): string { return d + this.#secret; }
}
const lvl: Level = 'low';
Результат:
"use strict";
class Tx {
id;
amount;
static count = 0;
#secret = 'k';
constructor(id, amount) {
this.id = id;
this.amount = amount;
Tx.count++;
}
get fee() { return this.amount * 0.001; }
sign(d) { return d + this.#secret; }
}
const lvl = 'low';
interface, type, implements, public, readonly, private, все аннотации типов — исчезли полностью. class, static, #secret — остались, потому что это возможности самого JavaScript.
Отсюда единственное практическое следствие, которое нужно запомнить накрепко: TypeScript ничего не проверяет во время работы программы. Ответ сервера, содержимое файла, аргументы из командной строки — всё это приходит без типов, и написанный вами type Tx = {...} не остановит мусор. Проверку данных на границе программы пишут руками или библиотекой вроде Zod.
Deno и Bun: попытки переделать Node
В 2018 году Райан Дал выступил с докладом о том, что он сам считает ошибками в Node.js: доступ к файлам и сети без всякого разрешения, громоздкая система модулей, папка node_modules размером с проект.
Из этого выросли две среды, которые вы наверняка встретите.
Deno (2020, тот же автор): права выдаются явно — без --allow-net программа в сеть не выйдет; TypeScript работает без настройки; стандартная библиотека своя.
Bun (первый выпуск 2022, версия 1.0 в 2023): ставка на скорость. Среда запуска, установщик пакетов, сборщик и запускалка тестов в одной программе; TypeScript тоже из коробки.
Стоит ли переходить: пока нет. Node.js остаётся тем, на чём работает подавляющее большинство проектов, в том числе блокчейн-SDK. Но знать про эти две среды нужно — и потому, что они встречаются в статьях, и потому, что они показывают, куда движется экосистема: разрешения по умолчанию и TypeScript без настройки постепенно перетекают и в Node.js.
Почему в языке столько странного: «не ломать веб»
Теперь можно вернуться к примерам из начала главы и объяснить каждый.
console.log(typeof null); // 'object'
Ошибка реализации 1995 года: значение null хранилось так, что проверка типа принимала его за объект. Исправить нельзя — тысячи страниц полагаются на текущее поведение. Предложение починить это обсуждалось и было отклонено.
console.log([] == false); // true
console.log('' == 0); // true
console.log(null == undefined); // true
console.log(null == 0); // false
Двойное равенство приводит операнды к общему типу по таблице правил из десяти пунктов. Правила придумывались в спешке и последовательными не получились: null равен undefined, но не равен нулю. Отсюда единственное разумное правило современного кода — всегда ===, а == оставить ровно для одной проверки: x == null ловит сразу null и undefined.
console.log([10, 1, 2].sort()); // [ 1, 10, 2 ]
sort без аргумента сравнивает элементы как строки. Решение 1995 года, менять нельзя.
console.log(typeof NaN); // 'number'
console.log(NaN === NaN); // false
«Не число» имеет тип «число», и оно не равно самому себе. Первое — следствие того, что NaN живёт внутри стандарта чисел IEEE 754, второе — прямое требование этого стандарта. Проверять нужно через Number.isNaN.
const f = () => {
return
42;
};
console.log(f()); // undefined
Автоматическая вставка точек с запятой: язык дописал ; сразу после return, и 42 стало недостижимым кодом. Живой запуск даёт undefined. Отсюда правило: значение пишут на той же строке, что и return.
console.log(Object.keys({ b: 1, a: 2, 1: 3, 0: 4 })); // [ '0', '1', 'b', 'a' ]
Ключи, похожие на целые числа, всегда идут первыми и по возрастанию — остальные в порядке добавления. Тоже наследие ранней реализации.
Общий вывод простой: язык нельзя чинить, его можно только дополнять. Все «исправления» последних тридцати лет — это новые конструкции рядом со старыми: === рядом с ==, let рядом с var, Number.isNaN рядом с isNaN, ?. рядом с ручными проверками. Старое остаётся навсегда, и знать его придётся хотя бы для чтения чужого кода.
Почему в блокчейне именно JavaScript и TypeScript
Вопрос законный: в блокчейне есть Rust, Go, Solidity, Ride. Откуда там JavaScript?
Ответ в разделении ролей. Языки вроде Solidity и Ride пишут то, что выполняется внутри блокчейна, — смарт-контракты. Всё остальное живёт снаружи, и там почти всегда JavaScript или TypeScript:
- клиентские библиотеки: SDK Waves Enterprise,
ethers.js,web3.js,viem— все на TypeScript; - интерфейсы: кошельки, обозреватели блоков, панели — это веб, а веб — это JavaScript;
- инструменты разработчика: Hardhat, Truffle — на Node.js;
- скрипты и автоматизация: выпустить токен, разослать транзакции, собрать статистику по блокам.
Причина ровно одна: там, где нужно и в браузере, и на сервере, и быстро — альтернатив немного. А TypeScript в этом наборе обязателен по отдельной причине: цена ошибки в коде, работающем с деньгами и ключами, высокая, и любая проверка, случающаяся до запуска, окупается мгновенно.
Что дальше: типы в самом JavaScript
Самое интересное предложение, которое сейчас обсуждается в TC39, — аннотации типов как комментарии. Замысел такой: разрешить писать типы прямо в файле .js, но договориться, что движок их полностью игнорирует — как игнорирует комментарии.
// как это выглядело бы
function fee(amount: number): number {
return amount * 0.001;
}
Движок пропустит : number мимо, а TypeScript, как и раньше, проверит. Выигрыш — исчезает шаг сборки: файл с типами можно запускать напрямую.
Предложение находится на ранней стадии, и попадёт ли оно в стандарт — неизвестно. Но направление видно и без него: Node.js уже умеет запускать файлы TypeScript, просто отбрасывая типы, а Deno и Bun делали это с самого начала. Похоже, что через несколько лет отдельный шаг компиляции для простых проектов исчезнет.
Второе заметное направление — скорость самого компилятора. Microsoft объявила о переписывании tsc на языке Go ради многократного ускорения проверки больших проектов; исходный компилятор написан на самом TypeScript, и на проектах в миллион строк это стало заметно.
Типичные заблуждения
| Заблуждение | Как на самом деле |
|---|---|
| «JavaScript — упрощённая Java» | Разные языки, общее только слово в названии, и то по маркетинговой договорённости 1995 года |
| «TypeScript — отдельный язык, надо учить заново» | Надстройка: любой корректный файл на JavaScript уже корректен на TypeScript |
| «TypeScript проверяет данные во время работы» | Все типы стираются при компиляции; данные с границы проверяют кодом |
| «ES6 — это версия JavaScript, а ES2015 — другая» | Одно и то же: ES6 — старое название, ES2015 — по году |
| «Раз есть ES2024, надо учить все версии» | Учат язык, а не версии; помнить нужно только границу 2015 года |
«var запрещён» | Не запрещён и работает до сих пор; просто ведёт себя иначе и в новом коде не нужен |
| «Node.js — это язык» | Это среда запуска: движок V8 плюс доступ к файлам, сети и процессам |
| «npm-пакет — это безопасно» | Это чужой код в вашей программе, и код его зависимостей тоже; left-pad показал цену |
| «Странности языка когда-нибудь исправят» | Не исправят: принцип «не ломать веб» сильнее. Добавят новое рядом со старым |
Тренажёр: даты и имена вслепую
Цель: скорость ≥ 110 зн/мин, точность ≥ 90%
1995 — Брендан Айк, первая версия за десять дней
Даты, которые стоит помнить
| Год | Событие | Почему важно |
|---|---|---|
| 1995 | Брендан Айк пишет первую версию за десять дней | Источник большинства странностей языка |
| 1995 | Mocha → LiveScript → JavaScript | Имя дано по маркетинговой договорённости с Sun |
| 1996 | JScript в Internet Explorer 3 | Начало войны браузеров и кода в двух вариантах |
| 1997 | ECMA-262, первая редакция | У языка появляется стандарт и второе имя |
| 1999 | ES3 | Опорная точка на десять лет |
| 2008 | ES4 закрыт | Номер 4 пропущен; типы в язык не попали |
| 2008 | V8 и JIT-компиляция | Язык стал быстрым, стало возможно всё остальное |
| 2009 | ES5 | Строгий режим, JSON, map/filter/reduce |
| 2009 | Node.js | JavaScript вышел за пределы браузера |
| 2010 | npm | Появилась экосистема пакетов |
| 2012 | TypeScript 0.8 | Типы как надстройка, а не новый язык |
| 2015 | ES6 / ES2015 | Граница старого и нового кода |
| 2016 | strictNullChecks | TypeScript начали воспринимать всерьёз |
| 2016 | случай с left-pad | Урок про доверие к зависимостям |
| 2017 | ES2017 | async/await |
| 2020 | ES2020, Deno 1.0 | ?. и ??; попытка переделать Node |
| 2022 | ES2022, первый Bun | #-поля класса; ставка на скорость |
| 2026 | TypeScript 6, ежегодные ES | Версия, стоящая в этом курсе |
Что должен уметь
- Рассказать, за какой срок и в какой компании появилась первая версия языка и как это отразилось на нём.
- Объяснить, почему язык называется JavaScript, и опровергнуть родство с Java.
- Различать имена «JavaScript» и «ECMAScript» и объяснить, откуда взялось второе.
- Рассказать, что случилось с ES4 и почему после ES3 идёт ES5.
- Объяснить, что сделал V8 в 2008 году и почему это ключевое событие.
- Объяснить, что такое Node.js, и не называть его языком.
- Назвать выводы из случая с
left-padи объяснить, зачем в репозиторииpackage-lock.json. - Назвать границу 2015 года и опознавать устаревший пример по слову
var. - Перечислить, что появилось в ES6, и объяснить, что каждое из этого заменило.
- Понимать годовую схему версий и не пытаться учить их по номерам.
- Объяснить, что означают стадии TC39, и определять, можно ли использовать возможность из статьи.
- Назвать принцип «не ломать веб» и объяснить через него
typeof null,==,sortи вставку точек с запятой. - Рассказать, из каких проблем вырос TypeScript и почему он сделан надстройкой.
- Объяснить, что даёт
strictNullChecksи почему эта версия считается переломной. - Показать на примере, что от типов не остаётся ничего после компиляции.
- Объяснить, почему тип не спасает от плохих данных, пришедших по сети.
- Назвать, чем известен Андерс Хейлсберг, и связать это со сходством TypeScript и C#.
- Отличать Deno и Bun от Node.js и объяснить, зачем они появились.
- Объяснить, почему в блокчейне клиентская часть почти всегда на TypeScript.
Углубиться
Почему typeof null даёт 'object'. В первой реализации значение хранилось как пара «метка типа + данные», и метка 000 означала объект. Нулевой указатель состоял из одних нулей, поэтому проверка типа честно видела метку объекта. Предложение исправить это выносилось на комитет и было отклонено: слишком много кода полагается на текущее поведение.
arguments и почему стрелки его не имеют. До ES6 у любой функции был скрытый объект arguments со всеми переданными значениями — так обходились без остаточных параметров. Стрелочные функции его не получили намеренно: у них нет ни своего this, ни arguments, и это делает их предсказуемыми.
Transpilers. С 2013 по 2018 год существовал целый жанр инструментов, переводивших новый JavaScript в старый: Traceur, затем Babel. Без них пользоваться ES6 было нельзя — браузеры не успевали. Сегодня Babel остался в основном ради JSX и совсем старых браузеров, а его роль перешла к более быстрым инструментам вроде esbuild и SWC.
CommonJS против модулей ES. Node.js в 2009 году не мог ждать стандартных модулей и придумал свои — require и module.exports. Стандартные import/export появились в 2015-м и оказались устроены иначе: они разбираются до выполнения файла. Две системы сосуществуют до сих пор, и большая часть настроечной боли в проектах на Node.js растёт именно отсюда.
JavaScript и другие «компилируемые в JS» языки. TypeScript был не первым: были GWT (Java в JS), CoffeeScript, Dart, Elm, ClojureScript, ReasonML. Победил тот, кто не требовал бросать существующий код и не изобретал новый синтаксис ради красоты.
WebAssembly. С 2017 года в браузере можно выполнять двоичный формат, в который компилируют Rust, C++ и Go. Это не замена JavaScript, а дополнение для тяжёлых вычислений: криптографии, обработки изображений, игр. В блокчейн-инструментах WebAssembly встречается регулярно — например, для проверки подписей в браузере.
Дальше по теме:
- MDN: история JavaScript — краткая официальная справка
- Список предложений TC39 — что сейчас на какой стадии
- Спецификация ECMAScript — сам стандарт; читать целиком не нужно, но полезно один раз увидеть
- Releases TypeScript — что появилось в каждой версии
Сводная проверка по всей главе: 18 вопросов, 5:00 на всё, без подсказок по ходу. Вопросы показываются по одному, ответ изменить нельзя. Если время выйдет — экзамен завершится с тем, что успел ответить. Пересдавать можно сколько угодно раз.
Куда дальше: проверенные ресурсы
-
Спецификация ECMAScript — действующий стандарт целиком.
-
Список предложений TC39 — что сейчас на какой стадии, с ссылками на обсуждения.
-
MDN: JavaScript — обзор — точка входа во всю документацию, на русском.
-
Release Notes TypeScript — что появилось в каждой версии, от авторов.
-
Документация Node.js — справочник по всему, чего нет в самом языке.
-
Learn JavaScript: введение — короткий русскоязычный обзор языка и стандарта.
-
Can I use — где какая возможность уже работает; ответ на вопрос «можно ли это уже писать».
-
Видео и материалы сообщества — ниже — ролики по теме и ссылки от студентов и преподавателей смотри в самом низу страницы.
Комментарии
Обсуждение живёт в GitHub Discussions и грузится с чужого домена — поэтому только по нажатию.