Ситуация: улучшаем код из статьи про автопереключение тёмной темы на сайте, чтобы одновременно работала ручная и автоматическая настройка. Идея такая: по нажатию автопереключателя добавлять в стили новый медиазапрос, чтобы браузер сам включал тёмную тему.
Идём на StackOverflow, находим готовое решение и правим под себя все названия переменных и функций:
// получаем доступ к таблице стилей
const styleSheet = style.sheet;
function autoDarkLight() {
console.log('Вставляем новый медиазапрос в стили');
// формируем стиль
const mediaRuleText = `@media screen and (prefers-color-scheme: dark) {
body {
background: black;
color: white;
}
}`;
// добавляем его в CSS
const mediaRuleIndex = styleSheet.insertRule(mediaRuleText);
}
Вставляем этот код в наш скрипт, обновляем страницу и нажимаем на переключатель, чтобы вызвать функцию autoDarkLight()
. Но вместо добавления запроса компьютер выдаёт ошибку:
❌ ReferenceError: Cannot access uninitialized variable.
Что это значит: JavaScript попытался получить доступ к переменной, но в момент обращения выяснилось, что она не инициализирована: браузер под неё не выделил память и работать с ней нельзя.
Что делать с ошибкой ReferenceError: Cannot access uninitialized variable
Хитрость этой ошибки в том, что чаще всего проблема не там, где произошла ошибка, а в другом месте кода. Например, вот что выдаёт нам браузер в консоли:
Видно, что функция начала работать, выдала сообщение в консоль, а потом остановилась на 50-й строке кода. Идём в редактор кода смотреть, что у нас там написано:
Получается, что браузер ругается на строку const mediaRuleIndex = styleSheet.insertRule(mediaRuleText)
, но с ней вроде всё в порядке:
- переменную
mediaRuleIndex
мы определяем прямо сейчас, поэтому проблема явно не в ней; - переменную
styleSheet
мы объявили в самом начале, когда вставили чужой фрагмент кода; - а
mediaRuleText
мы заполнили пятью строками выше, и с ней тоже всё хорошо.
На самом деле ошибка только проявилась в этой строке, но произошла она гораздо раньше, когда мы добавили в скрипт строку
const styleSheet = style.sheet;
Проблема с ней в том, что style
— это не встроенный стандартный элемент для обращения к CSS-стилям, а просто обычная новая переменная. Мы её никак не объявляли заранее и ничего ей не присваивали, а сразу начали использовать. Компьютер не выделил для неё память, а значит, что всё, что основано на этой переменной, например styleSheet
, тоже не инициализировано.
Именно по этой причине браузер ругается на строку 50, потому что ему говорят что-то сделать на основе неинициализированной переменной, а так нельзя.
Как исправить: правильно определить переменную style
:
const style = document.getElementsByTagName("style")[0];
Теперь браузер создаст новую переменную, выделит под неё память, наполнит нужными значениями и позволит что-то делать на её основе.
Задание со звёздочкой: попробуйте сами найти причину такой же ошибки в этом коде:
// main.js
import {createApp} from 'vue';
import App from 'components/App.vue';
// ...
// здесь компьютер выдаст ошибку
const application = createApp(App);