Як правильно перевірити тип змінної JavaScript. Динамічна ідентифікація типів Оператор отримання типу

Головна / Захист

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

Таблиця 14.5. Логічні оператори

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

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

&& І (логічне множення)

|| АБО (логічне додавання)

Таблиця 14.6. Результати виконання операторів І та АБО

Операнд 1

Операнд 2

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

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

Оператор отримання типуТипповертає рядок, що описує тип даних операнда. Операнд, тип якого потрібно дізнатися, поміщають після цього оператора і укладають у круглі дужки:

s = typeof("str");

В результаті виконання цього виразу в змінній s виявиться рядок "string", що позначає рядковий тип.

Усі значення, які може повернути оператор типу, перераховані в табл. 14.8.

Таблиця 14.8. Значення, що повертаються оператором типу

Тип даних

Повертається рядок

Рядковий

Числовий

Таблиця 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.

Частина ІІІ. Поведінка 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 до отриманої різниці.

Виходить зовсім інший результат, чи не так?

  • Undefined: "undefined"
  • Null: "object"
  • Boolean: "boolean"
  • Номер: "number"
  • String: "string"
  • Function: "function"
  • Решта: «object»

До цієї таблиці слід додати такі зауваження:

1. typeof null === "object" .

Теоретично тут тонкий момент. У мовах зі статичною типізацієюзмінна об'єктного типу може містити об'єкта (NULL, nil, нульовий покажчик).

Практично - JavaScript це незручно. Тому розробники ES 5.1 збираються зробити інтуїтивніше зрозумілу річ: typeof null === "null" .

Але оскільки у нас поки що навколо ES3, не помилитеся, наприклад, на такому:

/* Функція шукає якийсь об'єкт і повертає його чи null якщо нічого не знайдено */ function search() () var obj = search(); if (typeof obj === "object") ( // Чи дійсно ми знайшли об'єкт (FAIL) obj.method(); )

2. Не забуваємо про об'єкти-обертки (typeof new Number(5) === "object").

3. І не забуваємо на право браузерів творити будь-що з host-об'єктами.

Не дивуйтесь тому, що Safari завзято вважає HTMLCollection типом function , а IE раніше 9-ї версії тримають нашу улюблену функцію alert() за object . Також Chrome раніше вважав RegExp за function, але тепер, здається, опритомнів і відповідає на неї object.

toString()

Намагатися дізнатися тип значення результату його методу toString() безглуздо. У всіх класах цей метод перевизначений на свій.

Для виведення налагоджувальної інформації метод хороший, але типу змінної щодо нього не визначити.

Object.prototype.toString()

Хоча toString всередині конкретних «класів» перевизначено, ми все одно є його початкова реалізація з Object. Спробуємо скористатися нею:

console.log (Object.prototype.toString.call (value));

console.log(Object.prototype.toString.call(value));


Клінтон розбавляє цю тягомотину

Як не дивно, цей метод працює на подив добре.

Для скалярних типів повертає , , , .

Найсмішніше, що навіть new Number(5) на якому забоїв typeof тут повертає .

На null і undefined метод давати збої. Різні браузери повертають, то очікувані і, то, то взагалі. Втім, визначити тип цих двох значень легко можна і без цього.

Цікаве починається, коли ми підходимо до об'єктів (тим, у яких typeof === "object").

built-in об'єкти відпрацьовують практично на ура:

  • {} —
  • Date -
  • Error -
  • RegExp -

Єдине, випадає зі списку arguments , Що то , то .
З host-об'єктами знову все гірше.

У IE DOM-об'єкти стали ставати «нормальними» об'єктами лише з 8-ї версії, і то не зовсім до кінця. Тому в IE 6-8 всі ці об'єкти (HTMLCOllection, DOMElement, TextNode, а заодно document і window) наводяться просто до .

У всіх інших браузерах (включаючи IE9) з результатом toString вже можна щось робити. Хоча теж все непросто: HTMLCollection там, то. window - то, то, то. Але з цього вже можна спробувати щось вивудити.

Складніше з DOMElement: він виводиться як , — свій формат кожного тега. Але і тут регулярка нам допоможе.

З іншими host-об'єктами (в тестах location і navigator) приблизно теж історія. Скрізь, крім IE, їх можна ідентифікувати рядком.

З мінусів використання Object.prototype.toString():

1. Можливість ця не освячена стандартом. І ми тут повинні швидше радіти, що все так вдало працює, а не журитися з приводу деяких вад.

2. Визначення типу по синтаксичному розбору рядка, що повертається методом, який взагалі для визначення типу, та й ще викликається на об'єкті якого не належить, залишає деякий осад на душі.

3. У старих IE, очевидно, host-об'єкти нормально не ідентифікувати.

Однак це цілком робоча штука при використанні спільно з іншими засобами.


Конструктори

Ну і, зрештою, конструктори. Хто може краще сказати про «клас» об'єкта в JS, якщо не його конструктор?

У null і undefined немає об'єктів-оберток, ні конструкторів.

В інших скалярних типів обгортки є, відповідно, можна отримати і конструктор:

(5) .constructor === Number; (Number .NaN) .constructor === Number; (true) .constructor === Boolean; ("string") .constructor === String ;

(5).constructor === Номер; (Number.NaN).constructor === Number; (true).constructor === Boolean; ("string").constructor === String;

А ось устанції тут не пройде:

5 instanceof Number; // false Number .NaN instanceof Number; // false true instanceof Boolean; // false "string" instanceof String ; // false

5 instanceof Number; // false Number.NaN instanceof Number; // false true instanceof Boolean; // false "string" instanceof String; // false

(instanceof спрацює для багатостраждального new Number(5))

З функціями (які до того ж об'єкти) пройде і встановлення:

console.log ((function () ()) instanceof Function); // true console.log((function()()).constructor === Function); // true

console.log((function () ()) instanceof Function); // true console.log((function () ()).constructor === Function); // true

Всі об'єкти вбудованих класів також легко ідентифікуються за конструкторами: Array, Date, RegExp, Error.

Одна проблема виникає тут з arguments, конструктор якого Object.

А друга з самим Object , вірніше як віднести до нього об'єкт, створений через користувальницький конструктор.

Так можна визначити лише базовий об'єкт:

obj instanceof Object;

Як один із варіантів визначення - перебрати всі інші можливі типи (Array, Error...) і якщо ні під один не підпав - "object".

Конструктори та host-об'єкти

З host-об'єктами все гірше.

Почнемо з того, що IE до 7 версії включно їх взагалі за нормальні об'єкти не вважає. У них там просто немає конструкторів та прототипів (принаймні програмісту до них не достукатися).

В інших браузерах справи кращі. Конструктори є і з них можна визначити клас значення. Тільки називаються вони в різних браузерахпо різному. Наприклад для HTMLCollection конструктор буде або HTMLCollection або NodeList, а то й зовсім NodeListConstructor.

Також слід визначити базовий конструктор DOMElement. У FF це, наприклад, HTMLElement, від якого вже успадковуються HTMLDivElement та інші.

Підлянку підкидають FireFox нижче 10-ї версії та Opera нижче 11. Там конструктор колекції – Object.

constructor.name

Ще у конструкторів є властивість name, яка може бути корисною.

Воно містить ім'я функції-конструктора, наприклад (5).constructor.name === "Number" .

Однак:
1. У IE його немає взагалі, навіть у 9-му.
2. В Host-об'єкти браузери знову ліплять кожен що спроможний (а найчастіше ті взагалі не мають цієї якості). В Opera'і у DOMElement ім'я конструктора взагалі Function.prototype.
3. arguments знову "object".

Висновки

Жоден з представлених методів не дає стовідсоткового визначення типу/класу значення у всіх браузерах. Проте, разом вони дозволяють це зробити.

Найближчим часом спробую зібрати всі дані в таблички та навести приклад функції-визначниці.

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

Динамічна ідентифікація типів (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(); ) ) )

Результатом виконання цієї програми буде успішне перетворення.

JavaScriptабо JS(скорочено) не проста мова і розробники-початківці дізнаються про це не відразу. Спочатку вони дізнаються ази і все здається барвистим і прекрасним. Заходячи трохи глибше, з'являються JavaScript масиви, об'єкти, callback'і і таке інше, що часто виносить мозок.

У JavaScript важливо правильно перевіряти тип змінної. Допустимо ви хочете дізнатися чи є змінна масивом чи об'єктом? Як це правильно перевірити? У цьому конкретному випадку є хитрощі під час перевірки і саме про них буде цей запис. Давайте відразу приступимо.

Перевірка типу змінної

Наприклад, вам потрібно перевірити є змінна об'єктом, масивом, рядком або числом. Для цього можна використовувати тип, але вона не завжди видасть правду і в прикладі нижче я покажу чому.

Цей приклад я написав, щоб наочно показати, чому типне завжди правильний вибір.

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 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"; // Об'єкти типуз (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() === "функція"; typeof Math.sin === "function";

null

// Це було з народження JavaScript typeof null === "object";

У першій реалізації JavaScript значення були представлені парою тип тега та значення. Тип тега для об'єктів дорівнював 0. null був представлений як нульовий покажчик (0x00 у більшості платформ). Отже, тип тега для null дорівнював нулю, тому значення типу, що повертається, є фіктивним. ()

Виправлення було запропоновано в 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, гарантувалося, що оператор типуповерне рядок для будь-якого операнда, з яким він був викликаний. Це змінилося після додавання непідйомних оголошень let and const із блочною областю видимості. Тепер, якщо змінні оголошені за допомогою let і const , і для них викликаєтьсятип у блоці оголошення змінних, але до оголошення, то викидається ReferenceError . Поведінка відрізняється від неоголошених змінних, для яких типповерне "невизначений". Змінні з блочною областю видимості перебувають у " тимчасової мертвої зоні " , яка триває з початку блоку досі оголошення змінних. У цій зоні спроба доступу до змінних викидає виняток.

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
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome для AndroidFirefox для AndroidOpera для AndroidSafari on iOSSamsung InternetNode.js
typeofChrome Повна підтримка 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-об'єктів є об'єктами, але не функціями. Наприклад.

© 2022 androidas.ru - Все про Android