Домой /  Интернет / Javascript проверить тип переменной. JavaScript, typeof, типы и классы. Ошибки, связанные с временными мёртвыми зонами

Javascript проверить тип переменной. JavaScript, typeof, типы и классы. Ошибки, связанные с временными мёртвыми зонами

Динамическая идентификация типов

Динамическая идентификация типов (RTTI) позволяет определить тип объекта во время выполнения программы. Она оказывается полезной по целому ряду причин. В частности, по ссылке на базовый класс можно довольно точно определить тип объекта, доступного по этой ссылке. Динамическая идентификация типов позволяет также проверить заранее, насколько удачным будет исход приведения типов, предотвращая исключительную ситуацию в связи с неправильным приведением типов. Кроме того, динамическая идентификация типов является главной составляющей рефлексии.

Для поддержки динамической идентификации типов в C# предусмотрены три ключевых слова: is, as и typeof. Каждое из этих ключевых слов рассматривается далее по очереди.

Оператор is

Конкретный тип объекта можно определить с помощью оператора is. Ниже приведена его общая форма:

выражение is тип

где выражение обозначает отдельное выражение, описывающее объект, тип которого проверяется. Если выражение имеет совместимый или такой же тип, как и проверяемый тип, то результат этой операции получается истинным, в противном случае - ложным. Так, результат будет истинным, если выражение имеет проверяемый тип в той или иной форме. В операторе is оба типа определяются как совместимые, если они одного и того же типа или если предусмотрено преобразование ссылок, упаковка или распаковка.

Ниже приведен пример применения оператора is:

Using System; namespace ConsoleApplication1 { class Add { } class Sum: Add { } class Program { static void Main() { Add a = new Add(); Sum s = new Sum(); if (a is Add) Console.WriteLine("Переменная a имеет тип Add"); if (s is Sum) Console.WriteLine("Тип переменной s унаследован от класса Add"); Console.ReadLine(); } } }

Оператор as

Иногда преобразование типов требуется произвести во время выполнения, но не генерировать исключение, если исход этого преобразования окажется неудачным, что вполне возможно при приведении типов. Для этой цели служит оператор as, имеющий следующую общую форму:

выражение as тип

где выражение обозначает отдельное выражение, преобразуемое в указанный тип.

Если исход такого преобразования оказывается удачным, то возвращается ссылка на тип, а иначе - пустая ссылка. Оператор as может использоваться только для преобразования ссылок, идентичности, упаковки, распаковки. В некоторых случаях оператор as может служить удобной альтернативой оператору is. В качестве примера рассмотрим следующую программу:

Using System; namespace ConsoleApplication1 { class Add { } class Sum: Add { } class Program { static void Main() { Add a = new Add(); Sum s = new Sum(); // Выполняем приведение типов a = s as Add; if (a != null) Console.WriteLine("Преобразование прошло успешно"); else Console.WriteLine("Ошибка при преобразовании"); Console.ReadLine(); } } }

Результатом выполнения данной программы будет успешное преобразование.

a = (b > 0) && (c + 1 != d); flag = !(status = 0);

Таблица 14.5. Логические операторы

Оператор Описание

! НЕ (логическая инверсия)

&& И (логическое умножение)

|| ИЛИ (логическое сложение)

Таблица 14.6. Результаты выполнения операторов И и ИЛИ

Операнд 1

Операнд 2

Таблица 14.7. Результаты выполнения оператора НЕ

Оператор получения типа typeof

Оператор получения типа typeof возвращает строку, описывающую тип данных операнда. Операнд, тип которого нужно узнать, помещают после этого оператора и заключают в круглые скобки:

s = typeof("str");

В результате выполнения этого выражения в переменной s окажется строка "string" , обозначающая строковый тип.

Все значения, которые может вернуть оператор typeof , перечислены в табл. 14.8.

Таблица 14.8. Значения, возвращаемые оператором typeof

Тип данных

Возвращаемая строка

Строковый

Числовой

Таблица 14.8 (окончание)

Тип данных

Возвращаемая строка

Логический

Совместимость и преобразование типов данных

Настала пора рассмотреть еще два важных вопроса: совместимость типов данных и преобразование одного типа к другому.

Что получится, если сложить два числовых значения? Правильно - еще одно числовое значение. А если сложить число и строку? Трудно сказать... Тут JavaScript сталкивается с проблемой несовместимости типов данных и пытается сделать эти типы совместимыми, преобразуя один из них к другому. Сначала он пытается преобразовать строку в число и, если это удается, выполняет сложение. В случае неудачи число будет преобразовано в строку, и две полученные строки будут объединены. Например, в результате выполнения Web-сценария из листинга 14.6 значение переменной b при сложении с переменной a будет преобразовано в числовой тип; таким образом, переменная c будет содержать значение 23.

Листинг 14.6

var a, b, c, d, e, f; a = 11;

b = "12"; c = a + b;

d = "JavaScript"; e = 2;

Но поскольку значение переменной d нельзя преобразовать в число, значение e будет преобразовано в строку, и результат - значение f - станет равным

Логические величины преобразуются либо в числовые, либо в строковые, в зависимости от конкретного случая. Значение true будет преобразовано в число 1 или строку "1" , а значение false - в 0 или "0" . И наоборот, число 1 будет преобразовано в значение true , а число 0 - в значение false . Также в false будут преобразова-

ны значения null и undefined .

Часть III. Поведение Web-страниц. Web-сценарии

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

Приоритет операторов

Последний вопрос, который мы здесь разберем, - приоритет операторов. Как мы помним, приоритет влияет на порядок, в котором выполняются операторы в выражении.

Пусть имеется следующее выражение:

В этом случае сначала к значению переменной b будет прибавлено значение c , а потом из суммы будет вычтено 10. Операторы этого выражения имеют одинаковый приоритет и поэтому выполняются строго слева направо.

Теперь рассмотрим такое выражение:

Здесь сначала будет выполнено умножение значения c на 10, а уже потом к полученному произведению будет прибавлено значение b . Оператор умножения имеет больший приоритет, чем оператор сложения, поэтому порядок "строго слева направо" будет нарушен.

Самый низкий приоритет у операторов присваивания. Вот почему сначала вычисляется само выражение, а потом его результат присваивается переменной.

В общем, основной принцип выполнения всех операторов таков: сначала выполняются операторы с более высоким приоритетом, а уже потом - операторы с более низким. Операторы с одинаковым приоритетом выполняются в порядке их следования (слева направо).

В табл. 14.9 перечислены все изученные нами операторы в порядке убывания их приоритетов.

Таблица 14.9. Приоритет операторов (в порядке убывания)

Операторы

Описание

++ -- - ~ ! typeof

Инкремент, декремент, смена знака, логическое НЕ, определение типа

Умножение, деление, взятие остатка

Сложение и объединение строк, вычитание

Операторы сравнения

Логическое И

Глава 14. Введение в Web-программирование. Язык JavaScript

Таблица 14.9 (окончание)

Операторы

Описание

Логическое ИЛИ

Условный оператор (см. ниже)

= <оператор>=

Присваивание, простое и сложное

В НИМАНИЕ!

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

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

a = (b + c) * 10;

Здесь сначала будет выполнено сложение значений переменных b и c , а потом получившаяся сумма будет умножена на 10.

Операторы, заключенные в скобки, также подчиняются приоритету. Поэтому часто используются многократно вложенные скобки:

a = ((b + c) * 10 - d) / 2 + 9;

Здесь операторы будут выполнены в такой последовательности:

1. Сложение b и c .

2. Умножение полученной суммы на 10.

3. Вычитание d из произведения.

4. Деление разности на 2.

5. Прибавление 9 к частному.

Если удалить скобки:

a = b + c * 10 - d / 2 + 9;

то порядок выполнения операторов будет таким:

1. Умножение c и 10.

2. Деление d на 2.

3. Сложение b и произведения c и 10.

4. Вычитание из полученной суммы частного от деления d на 2.

5. Прибавление 9 к полученной разности.

Получается совсем другой результат, не так ли?

JavaScript или JS (сокращенно) не простой язык и начинающие разработчики узнают об этом не сразу. По началу они узнают азы и все кажется красочным и прекрасным. Заходя чуть глубже, появляются JavaScript массивы, объекты, callback’и и все подобное, что часто выносит мозг.

В JavaScript важно правильно проверять тип переменной. Допустим вы хотите узнать является ли переменная массивом или объектом? Как это правильно проверить? В этом конкретном случае, есть хитрости во время проверки и именно о них будет эта запись. Давайте сразу приступим.

Проверка типа переменной

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

Этот пример я написал, чтобы наглядно показать, почему typeof не всегда правильный выбор.

Var _comparison = { string: "строка", int: 99, float: 13.555, object: {hello: "привет"}, array: new Array(1, 2, 3) }; // Вернет массив с ключами объекта var _objKeys = Object.keys(_comparison); for(var i = 0; i <= _objKeys.length - 1; i++) { // выведем в консоль тип каждой переменной console.log(typeof _comparson[_objKeys[i]]); }

Результат выполнения кода:

String number number object object

Верно? — Нет, конечно. Есть две проблемы. Каждая из них будет подробно описана и предложено решение.

Первая проблема: float число, выводится как number

Comparison.float не является числом и вместо number должно быть float (число с плавающей точкой).Чтобы это исправить, можно создать функцию с проверкой как в коде ниже.

Var _floatNumber = 9.22; var _notFloatNumber = 9; console.log(isFloat(_floatNumber)); console.log(isFloat(_notFloatNumber)); console.log(isFloat("")); function isFloat(n){ return Number(n) === n && n % 1 !== 0; }

Функция isFloat() выполняет проверку всех значений на числа с плавающей точкой. Сначала проверяется равна ли переменная n числу (Number(n) === n) и если да, то делается еще одна проверка на деление с остатком и если остаток есть, то возвращается булевой (true или false ) результат (n % 1 !== 0).

В примере выше она возвращает true , false и false . Первое значение имеет float тип, второе нет — это обычное число и последнее всего лишь пустая строка, которая не подходит под правила.

Вторая проблема: массив определился как объект

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

Есть несколько способов для проверки переменной на тип массива.

Первый вариант (хороший вариант). Проверяем принадлежность data к массиву с помощью instanceof ().

Var data = new Array("hello", "world"); var isArr = data instanceof Array;

Второй вариант (хороший вариант). Метод Array.isArray() возвращает булевое значение, которе будет зависеть от того является ли переменная массивом или нет ().

Var data = new Array("hello", "world"); var isArr = Array.isArray(data);

Третий вариант (самый лучший, но длинный). Для удобности, вы можете сделать этот способ функцией. Используя Object, мы делаем . Если результат Object.prototype.toString.call(data) не равен значит переменная не массив ().

Var data = new Array("hello", "world"); var isArr = Object.prototype.toString.call(data) == ""; console.log(isArr);

Последний результат в виде удобной функции:

Function isArray(data) { return Object.prototype.toString.call(data) == "" }

Теперь вы можете вызвать функции isArray() и как аргумент задать массив или что-то иное и посмотреть результат.

Послесловие

Запись получилась достаточно большой, чем изначально задумывалась. Но я ей доволен, потому что она достаточно кратко и четко описывает затруднения при проверке переменных в JavaScript и как их обойти.

Если у вас остались какие-либо вопросы — пишите их ниже к этому записи. Я буду рад помочь.

Оператор typeof возвращает строку, указывающую тип операнда.

Синтаксис

Операнд следует за оператором typeof:

Typeof operand

Параметры

operand является выражением, представляющим объект или примитив , тип которого должен быть возвращен.

Описание

В следующей таблице приведены возможные возвращаемые значения typeof . Дополнительная информация о типах и примитивах находится на странице .

Примеры

// Числа typeof 37 === "number"; typeof 3.14 === "number"; typeof(42) === "number"; typeof Math.LN2 === "number"; typeof Infinity === "number"; typeof NaN === "number"; // несмотря на то, что это "Not-A-Number" (не число) typeof Number(1) === "number"; // никогда не используйте эту запись! // Строки typeof "" === "string"; typeof "bla" === "string"; typeof "1" === "string"; // обратите внимание, что число внутри строки всё равно имеет тип строки typeof (typeof 1) === "string"; // typeof всегда вернёт в этом случае строку typeof String("abc") === "string"; // никогда не используйте эту запись! // Booleans typeof true === "boolean"; typeof false === "boolean"; typeof Boolean(true) === "boolean"; // никогда не используйте эту запись! // Символы typeof Symbol() === "symbol" typeof Symbol("foo") === "symbol" typeof Symbol.iterator === "symbol" // Undefined typeof undefined === "undefined"; typeof declaredButUndefinedVariable === "undefined"; typeof undeclaredVariable === "undefined"; // Объекты typeof {a: 1} === "object"; // используйте Array.isArray или Object.prototype.toString.call // чтобы различить обычные объекты и массивы typeof === "object"; typeof new Date() === "object"; // То что ниже приводит к ошибкам и проблемам. Не используйте! typeof new Boolean(true) === "object"; typeof new Number(1) === "object"; typeof new String("abc") === "object"; // Функции typeof function() {} === "function"; typeof class C {} === "function"; typeof Math.sin === "function";

null

// Это было определено с рождения JavaScript typeof null === "object";

В первой реализации JavaScript значения были представлены парой тип тега и значение. Тип тега для объектов равнялся 0. null был представлен как нулевой указатель (0x00 в большинстве платформ). Следовательно, тип тега для null равнялся нулю, поэтому возвращаемое значение typeof является фиктивным. ()

Исправление было предложено в ECMAScript (через отключение), но было отклонено . Это привело бы к тому, что typeof null === "null" .

Использование оператора new

// Все функции-конструкторы, созданные с помощью "new", будут иметь тип "object" var str = new String("String"); var num = new Number(100); typeof str; // Вернёт "object" typeof num; // Вернёт "object" // Но существует исключение для конструктора Function var func = new Function(); typeof func; // Вернёт "function"

Регулярные выражения

Вызываемые регулярные выражения были нестандартным дополнением в некоторых браузерах.

Typeof /s/ === "function"; // Chrome 1-12 Не соответствует ECMAScript 5.1 typeof /s/ === "object"; // Firefox 5+ Соответствует ECMAScript 5.1

Ошибки, связанные с временными мёртвыми зонами

До ECMAScript 2015, гарантировалось, что оператор typeof вернёт строку для любого операнда, с которым он был вызван. Это изменилось после добавления неподнимающихся объявлений let and const с блочной областью видимости. Теперь, если переменные объявлены с помощью let и const , и для них вызывается typeof в блоке объявления переменных, но до объявления, то выбрасывается ReferenceError . Поведение отличается от необъявленных переменных, для которых typeof вернёт "undefined". Переменные с блочной областью видимости находятся в "временной мёртвой зоне ", которая длится от начала блока до момента объявления переменных. В этой зоне попытка доступа к переменным выбрасывает исключение.

Typeof undeclaredVariable === "undefined"; typeof newLetVariable; let newLetVariable; // ReferenceError typeof newConstVariable; const newConstVariable = "hello"; // ReferenceError

Исключения

Во всех текущих браузерах существует нестандартный host-объект document.all , который имеет тип Undefined.

Typeof document.all === "undefined";

Хотя спецификация разрешает собственные имена типов для нестандартных экзотических объектов, требуется чтобы эти имена отличались от предопределённых. Ситуация, когда document.all имеет тип undefined должна рассматриваться как исключительное нарушение правил.

Спецификации

Спецификация Статус Комментарии
ECMAScript Latest Draft (ECMA-262)
Черновик
ECMAScript 2015 (6th Edition, ECMA-262)
Определение "The typeof Operator" в этой спецификации.
Стандарт
ECMAScript 5.1 (ECMA-262)
Определение "The typeof Operator" в этой спецификации.
Стандарт
ECMAScript 3rd Edition (ECMA-262)
Определение "The typeof Operator" в этой спецификации.
Стандарт
ECMAScript 1st Edition (ECMA-262)
Определение "The typeof Operator" в этой спецификации.
Стандарт Изначальное определение. Реализовано в JavaScript 1.1

Совместимость с браузерами

Update compatibility data on GitHub

Компьютеры Мобильные Server
Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome для Android Firefox для Android Opera для Android Safari on iOS Samsung Internet Node.js
typeof Chrome Полная поддержка 1 Edge Полная поддержка 12 Firefox Полная поддержка 1 IE Полная поддержка 3 Opera Полная поддержка Да Safari Полная поддержка Да WebView Android Полная поддержка 1 Chrome Android Полная поддержка 18 Firefox Android Полная поддержка 4 Opera Android Полная поддержка Да Safari iOS Полная поддержка Да Samsung Internet Android Полная поддержка 1.0 nodejs Полная поддержка Да

Легенда

Полная поддержка Полная поддержка

IE-специфичные замечания

В IE 6, 7 и 8 многие host-объекты являются объектами, но не функциями. Например.