JavaScript: Uncaught ReferenceError - переменная не определена

mr. Cooper • 1 час назад • Веб-разработка
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 обычно оказывается конкретнее, чем кажется по красной строке в консоли. Браузер сообщает, что код попытался обратиться к имени, которого он в этот момент не видит.

Дальше нужно найти причину: переменная находится внутри другого блока, объявлена позже, названа иначе или должна была прийти из другого модуля.

Комментарии

Пока нет комментариев. Будьте первым, кто напишет.

Чтобы оставить комментарий, войдите в аккаунт.

Похожие статьи