Типы данных: [[Class]], instanceof и утки
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Более новая информация по этой теме находится на странице https://learn.javascript.ru/instanceof.
Время от времени бывает удобно создавать так называемые «полиморфные» функции, то есть такие, которые по-разному обрабатывают аргументы, в зависимости от их типа. Например, функция вывода может по-разному форматировать числа и даты.
Для реализации такой возможности нужен способ определить тип переменной.
Оператор typeof
Мы уже знакомы с простейшим способом – оператором typeof.
Оператор typeof надёжно работает с примитивными типами, кроме null , а также с функциями. Он возвращает для них тип в виде строки:
…Но все объекты, включая массивы и даты для typeof – на одно лицо, они имеют один тип ‘object’ :
Поэтому различить их при помощи typeof нельзя, и в этом его основной недостаток.
Секретное свойство [[Class]]
Для встроенных объектов есть одна «секретная» возможность узнать их тип, которая связана с методом toString .
Во всех встроенных объектах есть специальное свойство [[Class]] , в котором хранится информация о его типе или конструкторе.
Оно взято в квадратные скобки, так как это свойство – внутреннее. Явно получить его нельзя, но можно прочитать его «в обход», воспользовавшись методом toString стандартного объекта Object .
Его внутренняя реализация выводит [[Class]] в небольшом обрамлении, как "[object значение]" .
В первой строке мы взяли метод toString , принадлежащий именно стандартному объекту <> . Нам пришлось это сделать, так как у Date и Array – свои собственные методы toString , которые работают иначе.
Затем мы вызываем этот toString в контексте нужного объекта obj , и он возвращает его внутреннее, невидимое другими способами, свойство [[Class]] .
Для получения [[Class]] нужна именно внутренняя реализация toString стандартного объекта Object , другая не подойдёт.
К счастью, методы в JavaScript – это всего лишь функции-свойства объекта, которые можно скопировать в переменную и применить на другом объекте через call/apply . Что мы и делаем для <>.toString .
Метод также можно использовать с примитивами:
При тестировании кода в консоли вы можете обнаружить, что если ввести в командную строку <>.toString.call(. ) – будет ошибка. С другой стороны, вызов alert( <>.toString. ) – работает.
Эта ошибка возникает потому, что фигурные скобки < >в основном потоке кода интерпретируются как блок. Интерпретатор читает <>.toString.call(. ) так:
Фигурные скобки считаются объектом, только если они находятся в контексте выражения. В частности, оборачивание в скобки ( <>.toString. ) тоже сработает нормально.
Для большего удобства можно сделать функцию getClass , которая будет возвращать только сам [[Class]] :
Заметим, что свойство [[Class]] есть и доступно для чтения указанным способом – у всех встроенных объектов. Но его нет у объектов, которые создают наши функции. Точнее, оно есть, но равно всегда "Object" .
Поэтому узнать тип таким образом можно только для встроенных объектов.
Метод Array.isArray()
Для проверки типа на массив есть специальный метод: Array.isArray(arr) . Он возвращает true только если arr – массив:
Но этот метод – единственный в своём роде.
Других аналогичных, типа Object.isObject , Date.isDate – нет.
Оператор instanceof
Оператор instanceof позволяет проверить, создан ли объект данной функцией, причём работает для любых функций – как встроенных, так и наших.
Таким образом, instanceof , в отличие от [[Class]] и typeof может помочь выяснить тип для новых объектов, созданных нашими конструкторами.
Заметим, что оператор instanceof – сложнее, чем кажется. Он учитывает наследование, которое мы пока не проходили, но скоро изучим и затем вернёмся к instanceof в главе Проверка класса: "instanceof".
Утиная типизация
Альтернативный подход к типу – «утиная типизация», которая основана на одной известной пословице: «If it looks like a duck, swims like a duck and quacks like a duck, then it probably is a duck (who cares what it really is)».
В переводе: «Если это выглядит как утка, плавает как утка и крякает как утка, то, вероятно, это утка (какая разница, что это на самом деле)».
Смысл утиной типизации – в проверке необходимых методов и свойств.
Например, мы можем проверить, что объект – массив, не вызывая Array.isArray , а просто уточнив наличие важного для нас метода, например splice :
Обратите внимание – в if мы не вызываем метод something.splice() , а пробуем получить само свойство something.splice . Для массивов оно всегда есть и является функцией, т.е. даст в логическом контексте true .
Проверить на дату можно, определив наличие метода getTime :
С виду такая проверка хрупка, её можно «сломать», передав похожий объект с тем же методом.
Но как раз в этом и есть смысл утиной типизации: если объект похож на дату, у него есть методы даты, то будем работать с ним как с датой (какая разница, что это на самом деле).
То есть мы намеренно позволяем передать в код нечто менее конкретное, чем определённый тип, чтобы сделать его более универсальным.
Если говорить словами «классического программирования», то «duck typing» – это проверка реализации объектом требуемого интерфейса. Если реализует – ок, используем его. Если нет – значит это что-то другое.
Пример полиморфной функции
Пример полиморфной функции – sayHi(who) , которая будет говорить «Привет» своему аргументу, причём если передан массив – то «Привет» каждому:
Проверку на массив в этом примере можно заменить на «утиную» – нам ведь нужен только метод forEach :
Итого
Для написания полиморфных (это удобно!) функций нам нужна проверка типов.
Для примитивов с ней отлично справляется оператор typeof .
У него две особенности:
- Он считает null объектом, это внутренняя ошибка в языке.
- Для функций он возвращает function , по стандарту функция не считается базовым типом, но на практике это удобно и полезно.
Для встроенных объектов мы можем получить тип из скрытого свойства [[Class]] , при помощи вызова <>.toString.call(obj).slice(8, -1) . Для конструкторов, которые объявлены нами, [[Class]] всегда равно "Object" .
Оператор obj instanceof Func проверяет, создан ли объект obj функцией Func , работает для любых конструкторов. Более подробно мы разберём его в главе Проверка класса: "instanceof".
И, наконец, зачастую достаточно проверить не сам тип, а просто наличие нужных свойств или методов. Это называется «утиная типизация».
Задачи
Полиморфная функция formatDate
Напишите функцию formatDate(date) , которая возвращает дату в формате dd.mm.yy .
Её первый аргумент должен содержать дату в одном из видов:
- Как объект Date .
- Как строку, например yyyy-mm-dd или другую в стандартном формате даты.
- Как число секунд с 01.01.1970 .
- Как массив [гггг, мм, дд] , месяц начинается с нуля
Для этого вам понадобится определить тип данных аргумента и, при необходимости, преобразовать входные данные в нужный формат.
Для определения примитивного типа строка/число подойдёт оператор typeof.
Примеры его работы:
Оператор typeof не умеет различать разные типы объектов, они для него все на одно лицо: "object" . Поэтому он не сможет отличить Date от Array .
The typeof javaScript operator and other data type related things
The javaScript typeof operator will return a string that is the type of the operand that is given to it from the right of the typeof keyword when used in an expression. It is the first go to operator then to go about preforming type checking of values in javaScript.
However when it comes to data type checking in javaScript there are also some additional things to look out for when it comes to really knowing what one is dealing with when it comes to values. For example when it comes to objects the typeof operator will always return object, but will not give insight into the type of object. So the typeof operator is not a replacement for other keywords such as the instance of operator that will help to know what kind of object a value is when it is in fact an object.
The typeof operator might not always give the desired results in many cases. Maybe the most note worthy issue to be aware of is that it will return the value ‘object’ when used with a null value. This is actually the value that it should return, but some developers might considered this a bit confusion, and in any case it is something that one has to adjust for no matter what anyway.
1 — javaScript typeof lowdown
The typeof operator has right to left associativity so to use it I just need to type the typeof operator followed by what it is that I want to find the type of. the result of the expression of the typeof operator with the value I want the type of to the right of typeof will then evaluate to a string, and the string more often then not will be the type of the value. For the most part the typeof operator is fairly straight forward to use but it has a few quirks, so lets get into it by starting off with a basic example of javaScript typeof.
Here the javaScript typeof operator works as expected, I give it a number and it returns the string ‘number’. So far the type of operator works the way it should without issue. However there are certain values like NaN that stands for Not a Number yet its type if number. Things also get a little weird when I pass it the null value for example so lets continue looking at some more examples here.
2 — No need to call typeof as it is an operator and not a function
In some examples I see new javaScript developers placing parentheses around what it is that they want to find the type of. This is not necessary as the typeof operator is an operator and not a function. However in some cases you might still want to use parentheses as a way to group an expression as you might get undesired results.
So if you do need to group then use parentheses otherwise they are not needed.
3 — The deal with javaScript typeof and null
So there is something strange with the typeof operator and the value of null. When the value of null is what is used with the typeof operator the result is object.
From what I have gathered so far with the typeof null equals object deal in javaScript it it would seem that this is a mistake that dates all the way to the beginning of javaScript. However maybe object is an appropriate value to return considering that the value is often used as a placeholder for what should be an object. There is some talk as to the subject of if it will be fixed or not but so far it seems like that is not happening. Also it would not be a good idea to change it at this point as that would result in a whole world of code breaking, so it would seem that this is just once little thing that javaScript developers just need to adjust for when using typeof.
4 — The Instanceof operator is what can be used for finding out what kind of object I am dealing with
In most cases the typeof operator works just fine if I want to find out if something is a number, string, or an object. However if I want to find out what kind of object I am dealing with then in most cases typeof does not help much unless it the object is a function. When it comes to javaScript there are plain old objects that are cerated with the Object constructor, or the object literal syntax, but there is also a whole worlds of different kinds of objects created with a constructor function.
There are a number of built in constructor functions like Date, and Function, but it is also possible to create ones own Constructor functions also. So it is a good idea to know how to go about finding out what kind of object one is dealing with when type checking, there are a few ways to do this, but maybe the instanceof operator is the first and foremost option that will come up.
The instanceof operator accepts two operands one to the left that is what should be an object, and the other is a constructor function. If the variable or value that is being evaluated is an instance of the constructor then the expression will evaluate to true, else false.
5 — Constructor name
When dealing with an object another way to get the actual constructor name of the object rather than just always getting object is to look at the constructor property. All objects should have a constructor object that will contain the constructor function that was used to create the object. For example if it is a Date object then the constructor should be the Date constructor. There is then a name property of this object that is then the name of that constructor function that was used.
6 — Conclusion
So it would seem that the javaScript typeof operator can be used as a way to find out the type of something in javaScript, but it might not aways work as expected. In addition when it comes to objects it is vague and can even return a value of object for null, so it still needs to be used with other operators to find out more in these situations.
JavaScript might be a typeless language however that just means that a variable can be any type at any given moment, it does not meed that javaScript does not have types. There are a number of data types to be aware of, also the javaScript of today is not the javaScript of yesterday as new specs of javaScript keep coming out additional types are being added. One note worthy example of this might be the Big integer data type that has been introduced in recent years.
JavaScript TypeOf – How to Check the Type of a Variable or Object in JS

TAPAS ADHIKARY

Data types and type checking are fundamental aspects of any programming language.
Many programming languages like Java have strict type checking. This means that if a variable is defined with a specific type it can contain a value of only that type.
JavaScript, however, is a loosely typed (or dynamically typed) language. This means that a variable can contain a value of any type. JavaScript code can execute like this:
With this in mind, it is critical to know the type of a variable at any given time.
The type of a variable is determined by the type of the value assigned to it. JavaScript has a special operator called typeof which lets you get the type of any value.
In this article, we will learn how typeof is used, along with a few gotchas to watch out for.
JavaScript Data Types
Let’s take a quick look at JavaScript data types before we dig into the typeof operator.
In JavaScript, there are seven primitive types. A primitive is anything that is not an object. They are:
- String
- Number
- BigInt
- Symbol
- Boolean
- undefined
- null
Everything else is an object – even including array and function . An object is a collection of key-value pairs.
The JavaScript typeof Operator
The typeof operator takes only one operand (a unary operator). It evaluates the type of the operand and returns the result as a string. Here is how you use it when you’re evaluating the type of a number, 007.
There is alternative syntax for the typeof operator where you can use it like a function :
This syntax is useful when you want to evaluate an expression rather than a single value. Here is an example of that:
In the above example, the expression typeof 007 evaluates to the type number and returns the string ‘number’. typeof(‘number’) then results in ‘string’ .
Let’s look at another example to understand the importance of the parenthesis with the typeof operator.
If you omit the parenthesis, it will return, NaN (Not a Number):
This is because, first typeof 999 will result in a string, «number». The expression «number» — 32223 results in NaN as happens when you perform a subtraction operation between a string and number.
JavaScript typeof Examples
The following code snippet shows the type check result of various values using the typeof operator.
The table below shows the type-check values of typeof :
| TYPE | RETURN VALUE OF TYPEOF |
|---|---|
| String | ‘string’ |
| Number | ‘number’ |
| BigInt | ‘bigint’ |
| Symbol | ‘symbol’ |
| Boolean | ‘boolean’ |
| undefined | ‘undefined’ |
| Function object | ‘function’ |
| null | ‘object’ (see below!) |
| Any other objects | ‘object’ |
Common Gotchas with typeof
There are cases where the typeof operator may not return types you’d expect. This may cause confusion and errors. Here are a few cases.
The type of NaN is a number
The typeof NaN is ‘number’ . This is strange, as we shouldn’t be detecting a NaN using typeof . There are better ways to deal with it. We will see them in a minute.
The type of null is the object
In JavaScript, typeof null is an object which gives a wrong impression that, null is an object where it is a primitive value.
This result of typeof null is actually a bug in the language. There was an attempt made to fix it in past but it was rejected due to the backward compatibility issue.
The type of an undeclared variable is undefined
Before ES6, a type check on an undeclared variable used to result in ‘undefined’ . But this is not an error-safe way to deal with it.
With ES6 we can declare block-scoped variables with the let or const keywords. If you use them with the typeof operator before they are initialized, they will throw a ReferenceError .
The type of a constructor function is an object
All constructor functions, except for the Function constructor, will always be typeof ‘object’.
This may lead to some confusion, as we expect it to be the actual type (in the above example, a string type).
The type of an Array is an object
Though technically correct, this could be the most disappointing one. We want to differentiate between an Array and Object even if an Array is technically an Object in JavaScript.
Fortunately there are ways to detect an Array correctly. We will see that soon.
Beyond typeof – Better Type Checking
Now that we’ve seen some of the limitations with the typeof operator, let’s see how to fix them and do better type checking.
How to Detect NaN
In JavaScript, NaN is a special value. The value NaN represents the result of an arithmetic expression that can’t actually be represented. For example,
Also, if we perform any arithmetic operations with NaN , it will always result in a NaN .
The type checking on NaN using the typeof operator doesn’t help much as it returns the type as a ‘number’ . JavaScript has a global function called isNaN() to detect if a result is NaN.
But there is a problem here, too.
In ES6, the method isNaN() is added to the global Number object. This method is much more reliable and so it’s the preferred one.
Another interesting aspect of NaN is that it is the only JavaScript value that is never equal to any other values including itself. So this is another way to detect NaN for the environments where ES6 is not supported:
How to Detect null in JavaScript
We have seen, detecting null using the typeof operator is confusing. The preferred way to check if something is null is by using the strict equality operator( === ).
Make sure not to use the == by mistake. Using the == in place of === will result in misleading type detection.
How to Detect an Array in JavaScript
From ES6 onwards, we can detect an array using the Array.isArray method.
Prior to ES6, we could use the instanceof operator to determine an Array:
A Generic Solution to Type Checking in JavaScript
There is a way we can create a generic solution to type checking. Have a look at the method, Object.prototype.toString . This is very powerful and extremely useful for writing a utility method for type checking.
When Object.prototype.toString is invoked using call() or apply() , it returns the object type in the format: [object Type] . The Type part in the return value is the actual type.
Let’s see how it works with some examples:
So this means that if we just take the return string and take out the Type part, we will have the actual type. Here is an attempt to do this:
Now, we can use the typeCheck function to detect the types:
In Summary
To Summarize what we’ve learned in this article:
- JavaScript type checking is not as strict as other programming languages.
- Use the typeof operator for detecting types.
- There are two variants of the typeof operator syntax: typeof and typeof(expression) .
- The result of a typeof operator may be misleading at times. We need to rely on other available methods ( Number.isNaN , Array.isArry , and so on) in those cases.
- We can use Object.prototype.toString to create a generic type detection method.
Before we end.
Thank you for reading this far! Let’s connect. You can @ me on Twitter (@tapasadhikary) with comments.
You may also like these other articles:
That’s all for now. See you again with my next article soon. Until then, please take good care of yourself.
Javascript как узнать тип объекта
In this article, How to Check the Type of a Variable or Object in JavaScript? In JavaScript, the typeof operator is used to determine the typeof an object or variable. JavaScript, on the other hand, is a dynamically typed (or weakly typed) language. This indicates that a variable can have any type of value. The type of the value assigned to a variable determines the type of the variable.
The typeof operator in JavaScript allows you to determine the type of value or type of value that a variable contains . There is just one operand for the typeof operator (a unary operator), which takes one variable as input. It determines the operand’s type and a string is returned as a result.
Let’s understand the typeof operator using some examples:
Example 1: If a string variable is checked by typeof, the result will be “string”.