Оглавление
Где можно найти документацию по работе оператора typeof из JavaScript?
typeof — это зарезервированное слово в JavaScript
Оператор typeof и примитивные значения в JavaScript?
Главная особенность работы оператора typeof в JavaScript
Оператор typeof и функция в JavaScript?
constructor.name вместо typeof
Введение
Полезность или бесполезность оператора typeof
в JavaScript каждый должен определить для себя сам. В этой публикации я постараюсь со всех возможных сторон взглянуть на работу данного оператора. В сети мне довелось видеть много разнообразных мест его применения и не все из них мне понравились.
Большинство людей путают итог выполнения оператора с результатом получения имени конструктора класса объекта, на который ссылается переменная. Большинство просто хочет знать в каком конструкторе был создан объект.
Где можно найти документацию по работе оператора typeof из JavaScript?
Почему JavaScript лучше других языков программирования? Потому что у него есть качественная описательная техническая документация, которая называется ECMAScript. Если говорить точнее, то JavaScript просто использует наработки стандарта ECMAScript. Стандарт живой и постоянно обновляется и поддерживается редакторами.
В стандарте есть раздел «13 ECMAScript Language: Expressions«, который описывает различные «Выражения«. Это такое понятие языка — термин. Нас будет интересовать подраздел «13.5 Unary Operators«, который выделяет «Унарные Операторы«. Их идея заключается в том, что сначала мы пишем название оператора, затем справа ставим как минимум один пробел и затем пишем выражение. То есть унарный оператор работает с «чем-то» одним и это «что-то» находится справа от него.
Оператор typeof
описан в разделе «13.5.3 The typeof Operator«. Получается, что оператор typeof
является унарным оператором.
typeof — это зарезервированное слово в JavaScript
В стандарте ECMAScript существует понятие «Зарезервированные Слова» (ReservedWord). Это такие слова, которые нельзя использовать для именования переменных.
Вы не сможете объявить переменную с именем «typeof». Это будет синтаксической ошибкой. Среда выполнения кода вам этого не позволит сделать. Программа перестанет работать и всё завалится.
Результат работы выражений — синтаксическая ошибка «Uncaught SyntaxError: Unexpected token ‘typeof’«.
Оператор typeof и примитивные значения в JavaScript?
Стандарт ECMAScript вводит такое понятие как «Примитивные Значения» (primitive value). В разделе «6.1 ECMAScript Language Types» с ними можно ознакомиться подробнее.
На 2023 год их насчитывается семь штук:
- Undefined
- Null
- Boolean
- Number
- BigInt
- Symbol
- String
Оператор typeof
обрабатывает их все и возвращает строку с соответствующим названием типа, кроме null
.
Давайте проверим эту логику работы оператора typeof в консоли браузера.
typeof undefined; typeof null; typeof ''; typeof Symbol(); typeof true; typeof 234; typeof 567n;
Возвращённые результаты в строковом виде:
Давайте сопоставим результаты со стандартом:
Обратите внимание, что у примитива ‘symbol’ нет литерального обозначения на уровне языка. Создание Символа возможно только при помощи конструктора класса Symbol. Именно поэтому там круглые скобки. Все остальные значения были оформлены литерально (хотя это и не обязательно).
Очень интересным можно отметить возвращение строки ‘object‘, при передачи в typeof
значения null
в качестве единственного операнда. Причём тут ‘object‘? Вообще не понятно. Но важно то, что если мы действительно передадим какой-то объект, то в ответ тоже получим строку ‘object‘.
В итоге становится не понятно что с чем сравнивать. То есть если мы в качестве операнда будем использовать ссылку на объект (на данные), то мы НЕ сможем отличить null
от объекта. Пример ниже:
let a = {a:1}; let b = null; typeof a; // 'object' typeof b; // 'object'
Скриншот:
Главная особенность работы оператора typeof в JavaScript
Единственное, чем выделяется typeof
на фоне своих собратьев, так это то, что он умеет безопасно заглядывать в список зарегистрированных имён переменных в среде выполнения кода. Именно «Заглядывать».
На втором шаге своего алгоритма проверяется на принадлежность к Ссылочной Записи в среде выполнения кода. В нашем случае мы указываем желаемый идентификатор — ссылку. В этот момент срабатывает ещё одно условие ветвления, которое прогоняет нашу ссылку (идентификатор) через абстрактную операцию IsUnresolvableReference(v).
Абстрактная операция IsUnresolvableReference принимает аргумент V (ссылочная запись) и возвращает логическое значение. При вызове она выполняет следующие действия:
Что нам это даёт? Через оператор typeof
мы можем проверять существование переменной в JavaScript. Но с подвохом.
Представим, что мы объявили только одну переменную, а пытаемся обратиться к двум именам переменных через оператор typeof
. Что мы получим?
let x; typeof x; typeof y;
Результаты вызовов:
В обоих случаях мы получаем строку «undefined«. И эта строка не даёт нам 100% ответа о том, есть ли искомый нами идентификатор привязки или нет его. В итоге мы всё равно не можем понять можно ли безопасно обратиться к этому имени переменной или нет. Именно поэтому typeof
только «заглядывает«, не «смотрит» внимательно.
Результат, строковое «undefined«, не отвечает нам конкретно:
- это значение undefined у переменной? (то есть переменная была объявлена, но ей не присвоилось никакого значения)
- или
- это отсутствие переменной вовсе? (ни имени, ни значения)
Оператор typeof и функция в JavaScript?
Алгоритм оператора typeof
предполагает отдельное условие для обработки функции в качестве операнда:
typeof function(){}; typeof (()=>{});
Мы делаем вызовы с обычной и стрелочной функциями. У таких функциональных объектов есть внутренний слот [[Call]], поэтому typeof
отличает их от всех остальных объектов.
В результате мы получаем строку «function«.
constructor.name вместо typeof
Иногда нам нужно проверять к какому классу принадлежит объект. То есть мы хотим понимать в конструкторе какого класса он был создан.
Для этого нужно использовать объект constructor, который доступен всем реальным объектам JavaScript.
let r = []; let o = {}; let x = null; let q = undefined; let w;
Смотрим на вызовы:
r?.constructor?.name; o?.constructor?.name; x?.constructor?.name; q?.constructor?.name; w?.constructor?.name;
ВПыва
Информационные ссылки
Стандарт ECMAScript — https://tc39.es/ecma262/multipage/