Ключевые слова JavaScript: полный список и ловушки
Содержание
О проверке кода. Примеры не запускались — в отличие от материалов по Node.js, где приводится фактический вывод. Говорим прямо, а не ставим бейдж «проверено» без проверки.
Тема выглядит справочной — список слов, который нужно один раз посмотреть. На деле в ней три ловушки, из-за которых код ведёт себя необъяснимо.
Полный список
Ключевые слова языка:
break case catch class const continue
debugger default delete do else export
extends false finally for function if
import in instanceof new null return
super switch this throw true try
typeof var void while with
Контекстные — ключевые не везде:
let static yield await async get set of
Зарезервированы про запас — в языке не используются:
enum implements interface package private protected public
enum зарезервирован с ES3, то есть больше двадцати лет, и не использован до сих пор. Комитет держит слова занятыми на случай будущих возможностей — дешевле запретить сразу, чем сломать чужой код потом.
Ключевые языка
Заняты грамматикой — имя переменной нельзя
class,for,function,returnconst,new,this,typeofconst class = 1→ SyntaxError- Свойством объекта — можно (ES5+)
Контекстные
Ключевые только в своём окружении
await— внутриasyncи модуляyield— внутри генератораlet,static— в строгом режиме и классе- Вне контекста — обычное имя
Про запас
Зарезервированы, но не используются
enum— занят с ES3, не задействованimplements,interface,packageprivate,protected,public- Держат на будущее
Ловушка первая: контекстные слова
Самое неочевидное. Одно и то же слово может быть ключевым или обычным именем — в зависимости от того, где стоит.
// в обычном скрипте это легально
function old() {
var await = 5; // ✅ await — просто имя
console.log(await); // 5
}
// а здесь — синтаксическая ошибка
async function modern() {
var await = 5; // ❌ SyntaxError
}
То же с yield — он ключевой только внутри генератора, и с static — только внутри класса.
Зачем такая сложность? Ради обратной совместимости. Когда в ES2017 добавляли async/await, в мире уже был код с переменной await. Сделай комитет слово безусловно ключевым — этот код сломался бы при обновлении браузера. Контекстность позволила добавить возможность, ничего не поломав.
let — из той же истории: вне строгого режима var let = 1; всё ещё работает.
Ловушка вторая: свойства — можно
// ❌ имя переменной
const class = 'card'; // SyntaxError
// ✅ свойство объекта — легально
const el = { class: 'card', new: true, for: 'name' };
el.class; // 'card'
el['class']; // то же самое
С ES5 ключевые слова разрешены в качестве имён свойств. До этого писали obj['class'] через скобки, а obj.class было ошибкой — след этого до сих пор виден в старом коде.
Именно поэтому в DOM свойство называется className, а не class: API придумывали до ES5, когда el.class был синтаксической ошибкой. Историческая причина, которая пережила саму проблему — подробнее в разборе работы с классами.
По той же причине у метки формы htmlFor, а не for.
Ловушка третья: undefined — не ключевое слово
Самое странное в этом списке.
typeof null; // "object" ← знаменитая ошибка, которую не стали чинить
typeof undefined; // "undefined"
null — ключевое слово, литерал. Его нельзя переопределить, null = 5 даст ошибку.
undefined — не ключевое слово. Это свойство глобального объекта, и в старом коде вне строгого режима его можно было переприсвоить:
// в древнем коде это работало и ломало всё вокруг
undefined = 5;
if (x === undefined) { ... } // сравнение с пятёркой!
Отсюда взялся приём, который до сих пор встречается в минифицированных библиотеках:
if (x === void 0) { ... } // void 0 ВСЕГДА undefined, переопределить нельзя
void — ключевое слово, поэтому void 0 надёжен. Сегодня в модулях и строгом режиме undefined защищён, и трюк не нужен — но в чужом коде вы его увидите.
Что нельзя называть, даже если можно
Формально легально, практически — беда:
const name = 'Аня'; // перекрывает window.name в браузере
const length = 10; // внутри функции перекроет arguments.length
const top = 1; // window.top — ссылка на верхнее окно
Это не ключевые слова, а свойства окружения. Ошибки не будет — будет необъяснимое поведение через полгода.
Отдельно: this и super не только ключевые, но и меняют смысл в зависимости от места. this в стрелочной функции берётся снаружи, в обычной — зависит от вызова.
Что было на этой странице в 2017 году
Первая версия вышла 20 июля 2017 года и давала список слов с пометкой, что их нельзя использовать как имена. Список верный, и большая его часть не изменилась.
Что изменилось:
- Добавились контекстные
asyncиawait— их в 2017-м в списке не было, потому что ES2017 только вышел. - Не было объяснения самой механики контекстности. Слова подавались как плоский список запретов, а тонкость «
awaitключевой только внутриasync» — именно та, из-за которой старый код не сломался. - Не было
undefinedпротивnull. А это единственное место в теме, где непонимание приводит к реальным багам.
Список ключевых слов — та часть языка, которая почти не меняется: добавить слово безусловно ключевым означает сломать чужой код. Поэтому всё новое приходит контекстным, и, скорее всего, так будет и дальше.
Смежные темы: что такое JavaScript; ECMAScript 6 — откуда взялись let и const; массивы; уроки JavaScript.
Частые вопросы
Почему `class` нельзя использовать как имя переменной, а `name` можно?
class — ключевое слово языка, оно занято грамматикой. name — просто свойство глобального объекта в браузере; переменная с таким именем его перекроет, что легально, но может выйти боком.`await` — ключевое слово или нет?
async-функции и на верхнем уровне модуля — ключевое; в обычной функции старого скрипта это просто имя. Поэтому старый код с переменной await не сломался при появлении async/await.Правда, что `undefined` можно переопределить?
undefined был обычным глобальным свойством. Отсюда старый приём void 0 вместо него. Сегодня в модулях и строгом режиме это невозможно.Зачем зарезервированы слова, которых в языке нет — `enum`, `implements`?
enum зарезервирован с ES3 и не использован до сих пор.Можно ли назвать свойство объекта ключевым словом?
obj.class и { new: 1 } легальны. Ограничение осталось только на имена переменных, функций и параметров.