JavaScript: Uncaught ReferenceError - переменная не определена
Uncaught ReferenceError: userName is not defined - одна из тех ошибок JavaScript, которые заставляют лишний раз перепроверить собственный код. Особенно когда userName действительно объявлена.
//js
function getUser() {
const userName = "Stanly";
}
getUser();
console.log(userName);Здесь нет опечатки. const userName есть, функция вызывается, но выполнение всё равно заканчивается ReferenceError.
Причина в области видимости: userName принадлежит функции getUser() и за её пределами недоступна. JavaScript не видит переменную только потому, что она где-то объявлена в этом же файле.
На практике такая ошибка возникает по нескольким причинам. Переменная может находиться внутри функции или блока, её имя может отличаться одной буквой, обращение к ней может происходить раньше объявления или она вообще может находиться в другом модуле.
Поэтому is not defined не всегда означает, что объявление забыли написать. Иногда оно есть, но в конкретной строке переменная недоступна.
Где именно живёт переменная
С функциями это встречается постоянно:
//js
function calculate() {
const price = 1500;
return price;
}
console.log(price);price существует внутри calculate, но наружу не выходит.
Если значение нужно использовать после вызова функции, его можно вернуть:
//js
function calculate() {
const price = 1500;
return price;
}
const price = calculate();
console.log(price);Теперь price во внешнем коде - уже отдельная переменная, получившая результат работы функции.
То же самое происходит с блоками:
//js
if (true) {
const message = "Привет";
}
console.log(message);Здесь message существует только между фигурными скобками.
С let поведение такое же:
//js
{
let count = 10;
}
console.log(count);Поэтому при ReferenceError полезно сначала найти объявление переменной и посмотреть, где именно оно находится.
А иногда проблема вообще в имени
Вот такой код выглядит почти нормально:
//js
const userName = "Stanly";
console.log(username);Но userName и username - разные идентификаторы.
С регистром ситуация такая же:
//js
const userName = "Stanly";
console.log(UserName);JavaScript не пытается догадаться, что имелось в виду.
Если в консоли написано:
//text
userName is not definedимеет смысл проверить именно userName: каждую букву, регистр и место объявления.
В небольшом примере такая ошибка очевидна. В реальном коде, где одна переменная используется в разных местах, её легко не заметить.
Бывает, что переменная объявлена, но слишком поздно
Например:
//js
console.log(userName);
const userName = "Stanly";В консоли появится:
//text
Uncaught ReferenceError: Cannot access 'userName' before initializationЭто уже немного другой случай.
JavaScript знает, что userName существует, но выполнение дошло до console.log раньше, чем переменная была инициализирована.
С let происходит то же:
//js
console.log(count);
let count = 10;Поэтому для let и const важно не только наличие объявления, но и порядок выполнения кода.
Почему HTML-элемент тоже может привести к ReferenceError
Допустим, в странице есть:
//html
<button id="saveButton">Сохранить</button>И в JavaScript написано:
//js
saveButton.addEventListener("click", () => {
console.log("Сохранено");
});Здесь легко решить, что saveButton уже существует - ведь такой id есть в HTML.
Но наличие элемента на странице не означает, что мы создали JavaScript-переменную с таким именем.
Надёжнее сделать это явно:
//js
const saveButton = document.querySelector("#saveButton");
saveButton.addEventListener("click", () => {
console.log("Сохранено");
});Теперь понятно, откуда появилась переменная saveButton.
Почему ошибка появляется только после клика
Иногда страница загружается нормально, а красная ошибка возникает только после действия пользователя.
Например:
//js
button.addEventListener("click", () => {
console.log(currentUser);
});При загрузке страницы эта строка внутри функции ещё не выполнялась.
Нажали кнопку - функция запустилась:
//text
Uncaught ReferenceError: currentUser is not definedПоэтому кажется, что проблему вызвал сам клик. На самом деле ошибка находилась в обработчике, просто браузер дошёл до неё только после события click.
Здесь стоит проверить строку внутри обработчика и область видимости переменной currentUser.
Переменная из другого файла сама собой не появится
Ещё одна распространённая история - переход на модули.
Есть файл user.js:
//js
const userName = "Stanly";И есть app.js:
//js
console.log(userName);Если это ES-модули, userName из первого файла не становится автоматически доступной во втором.
Нужно явно связать эти файлы.
user.js:
//js
export const userName = "Stanly";app.js:
//js
import { userName } from "./user.js";
console.log(userName);Здесь один файл экспортирует переменную, а другой её импортирует.
Не путайте ReferenceError с TypeError
Есть ещё одна деталь, из-за которой похожие ошибки часто смешивают.
//js
const user = undefined;
console.log(user.name);Переменная user здесь существует. JavaScript её нашёл.
Проблема в значении: внутри user находится undefined, поэтому обращение к name заканчивается TypeError.
А здесь:
//js
console.log(user);если user вообще нигде не объявлена, получится ReferenceError.
Разница простая: в первом случае переменная существует, но с её значением нельзя выполнить нужную операцию. Во втором JavaScript не может найти само имя.
Что проверять в первую очередь
Когда браузер пишет:
//text
Uncaught ReferenceError: something is not definedсначала найдите something.
Посмотрите, где она объявлена. Если объявление есть, проверьте область видимости. Затем - порядок выполнения. Если переменная должна приходить из другого файла, проверьте import и export. Если речь о DOM, посмотрите, где элемент превращается в JavaScript-переменную.
Отдельно проверьте написание имени. Лишняя буква или другой регистр вполне могут привести к ReferenceError.
ReferenceError обычно оказывается конкретнее, чем кажется по красной строке в консоли. Браузер сообщает, что код попытался обратиться к имени, которого он в этот момент не видит.
Дальше нужно найти причину: переменная находится внутри другого блока, объявлена позже, названа иначе или должна была прийти из другого модуля.
Комментарии
Чтобы оставить комментарий, войдите в аккаунт.