JavaScript | Как проверить существование переменной?

JavaScript | Как проверить существование переменной?

Введение

Прежде чем проверять существование имени переменной, нужно чётко понимать разницу между способами объявления этой переменной. Если говорить точнее, то нужно различать способы регистрации нового идентификатора привязки. Я говорю о таких словах как var, let, const. Учитывайте то, что только слово var является зарезервированным словом, а слова let и const не являются зарезервированными.

JavaScript полностью опирается на стандарт ECMAScript. Это значит, что любая среда выполнения JavaScript кода, должна учитывать языковые особенности языка ECMAScript. Более конкретно — нужно учитывать типы данных самой спецификации. На март 2023 года их существует 13 штук:

  1. The Enum Specification Type
  2. The List and Record Specification Types
  3. The Set and Relation Specification Types
  4. The Completion Record Specification Type
  5. The Reference Record Specification Type
  6. The Property Descriptor Specification Type
  7. The Environment Record Specification Type
  8. The Abstract Closure Specification Type
  9. Data Blocks
  10. The PrivateElement Specification Type
  11. The ClassFieldDefinition Record Specification Type
  12. Private Names
  13. The ClassStaticBlockDefinition Record Specification Type

 

Для проверки существования переменной (имени идентификатора привязки) нам нужно знать о существовании типа данных «Reference Record» (Ссылочная Запись) из стандарта ECMAScript. Любой браузер «под капотом» реализовывает весь этот функционал.

Если в среде выполнения кода не будет зарегистрирована Ссылочная Запись с нужным вам именем переменной (например именем my_qwe), то при обращении к ней вы будете получать ошибку вида «Uncaught ReferenceError: my_qwe is not defined«.

Получили ошибку вида ReferenceError при обращении к несуществующей переменной - JavaScript
Получили ошибку вида ReferenceError при обращении к несуществующей переменной — JavaScript

Для примера я использую консоль браузера, чтобы выводить результаты работы выражений. Мы попытались обратиться к переменной с именем «my_qwe«, но в ответ получили ошибку «ReferenceError«. Это значит, что вся наша программа перестала работать.

Ошибки тоже являются встроенными объектами в JavaScript. Все возможные ошибки среды выполнения кода описаны в стандарте ECMAScript.

Всего существует 6 стандартных видов ошибок, которые умеет распознавать ECMAScript:

  • EvalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

Ниже скриншот из стандарта

6 видов стандартных ошибок, которые распознаёт ECMAScript
6 видов стандартных ошибок, которые распознаёт ECMAScript

В JavaScript их будет гораздо больше из-за прикладных интерфейсов программирования так как они существенно расширяют глобальный объект.

Мы получили ошибку вида «ReferenceError». В стандарте это описано как: «Указывает, что обнаружена недопустимая ссылка.».

 

 

Проверка существования переменной через перехват ошибки оператором try catch в JavaScript

Для безопасного обращения к несуществующему имени переменной можно использовать оператор try и перехватывать ошибки:

try{my_qwe; console.log('Переменная определена')}catch{console.log('Переменная НЕ определена')}

Такое выражение будет более информативным.

Безопасно проверили существование переменной через оператор try catch в JavaScript
Безопасно проверили существование переменной через оператор try catch в JavaScript

Важно здесь то, что ошибка всё равно произошла! Но в этот раз мы её перехватили и корректно обработали своим алгоритмом. Это значит, что наша программа устояла перед проблемой.

 

Функция проверки существования переменной в JavaScript

Мы могли бы создать функцию проверки. Наша функция будет принимать потенциальное имя переменной. Возвращать будет логическое значение.

function isReferenceExists(ref){
   try{return ref, true}
   catch{return false}
}

Тестируем нашу функцию:

let a = 1;
isReferenceExists(a);
isReferenceExists(b);

Результат работы:

Ошибка при вызове функции с несуществующим идентификатором привязки - JavaScript
Ошибка при вызове функции с несуществующим идентификатором привязки — JavaScript

В таком виде это не будет работать ровно по той же причине, с которой мы начинали. Передавая «что-то» в функцию, нужно чтобы у этого «чего-то» был идентификатор привязки. То есть в момент вызова функции её параметр не сможет вычислиться. Ссылки нет.

 

Проверка существования переменной через оператор typeof в JavaScript

Давайте сразу смотреть на логику работы оператора typeof по стандарту ECMAScript.

Алгоритм работы оператора typeof - ECMAScript
Алгоритм работы оператора typeof — ECMAScript

На первом шаге работы оператора typeof, его функция пытается «Оценить» синтаксически унарное выражение, которое находится справа от токена «typeof». Результат «Оценки» падает в локальную переменную «val«.

На втором шаге результат «Оценки» проверяется на принадлежность к Ссылочной Записи в среде выполнения кода. В нашем случае мы указываем желаемый идентификатор — ссылку. В этот момент срабатывает ещё одно условие ветвления, которое прогоняет нашу ссылку (идентификатор) через абстрактную операцию IsUnresolvableReference(v).

Абстрактная операция IsUnresolvableReference принимает аргумент V (ссылочная запись) и возвращает логическое значение. При вызове она выполняет следующие действия:

Логика работы абстрактной операции IsUnresolvableReference для Ссылочной Записи по стандарту ECMAScript
Логика работы абстрактной операции IsUnresolvableReference для Ссылочной Записи по стандарту ECMAScript

 

В нашем случае ссылка окажется «неразрешимой» (unresolvable), абстрактная операция вернёт true, а затем во втором шаге работы функции оператора typeof мы внезапно завершим её выполнение и нам вернётся undefined.

И вот тут кроется проблема. Давайте смотреть на пример:

let x;
typeof x;
typeof y;

Что мы получили из двух вызовов оператора typeof?

Оператор typeof не может гарантировать наличие или отсутствие идентификатора привязки -имени переменной в среде - JavaScript
Оператор typeof не может гарантировать наличие или отсутствие идентификатора привязки -имени переменной в среде — JavaScript

В обоих случаях мы получаем строку «undefined». И эта строка не даёт нам 100% ответа о том, есть ли искомый нами идентификатор привязки или нет его. В итоге мы всё равно не можем понять можно ли безопасно обратиться к этому имени переменной или нет. Очень похоже на то, что кто-то из разработчиков стандарта поленился над предложенными вариантами, либо я чего-то не знаю. Можно было просто вернуть пустую строку хотя бы и тогда можно было бы точно сказать, что такого имени переменой в этом окружении нет.

Использование этого способа сомнительно, но где-то может работать. Если в программе все переменные будут сразу получать какие-то значения, тогда будет работать. Простое же объявление без присваивания обречено.

Оператор сравнения с оператором typeof - JavaScript
Оператор сравнения с оператором typeof — JavaScript

 

Зачем проверять существование переменной в среде выполнения JavaScript кода?

Написание программ и классов — это искусство. Главной мерой качественного манипулирования с языком JavaScript является устойчивость написанных вами программ.

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

Проверка существования переменных является важным знанием в процессе слияния работы нескольких программ друг с другом. Эти разные программы могут быть написаны как одним человеком в разное время, так и несколькими людьми. Иногда слияние требует использование «чужих» переменных, которые могут «потеряться» при слиянии и переносе.

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

 

Ключевые слова

Как безопасно обратиться к имени переменной, чтобы не получить ошибку?

 

Информационные ссылки

Стандарт ECMAScripthttps://tc39.es/ecma262/multipage/