Javascript check variable type. Dynamic Type Identification

  • undefined: "undefined"
  • Null: "object"
  • Boolean: "boolean"
  • Number: "number"
  • String: "string"
  • Function: "function"
  • Everything else: "object"

The following remarks should be added to this table:

1. typeof null === "object" .

Theoretically, there is a subtle point here. In statically typed languages, an object type variable may not contain an object (NULL, nil, null pointer).

Practically - in JavaScript it is inconvenient. So the ES 5.1 developers are going to do something more intuitive: typeof null === "null" .

But since we are still around ES3, make no mistake, for example, on this:

/* Function searches for some object and returns it or null if nothing is found */ function search() () var obj = search(); if (typeof obj === "object") ( // did we really find the object (FAIL) obj.method(); )

2. Don't forget about wrapper objects (typeof new Number(5) === "object").

3. And do not forget the right of browsers to do anything with host-objects.

Don't be surprised that Safari stubbornly treats HTMLCollection as a function type, and pre-9th IE keeps our favorite alert() function as an object . Also, Chrome used to consider RegExp to be a function , but now it seems to come to its senses and responds to it with an object .

toString()

Trying to find out the type of a value from the result of its toString() method is pointless. In all "classes" this method is redefined to its own.

The method is good for displaying debugging information, but the type of the variable cannot be determined from it.

Object.prototype.toString()

Even though toString is overridden inside concrete "classes", we still have its original implementation from Object. Let's try to use it:

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

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


Clinton dilutes this burden

Oddly enough, this method works surprisingly well.

For scalar types, returns , , , .

The funny thing is that even new Number(5) on which typeof failed here returns .

On null and undefined the method will fail. Different browsers return either expected and , or , or even . However, it is easy to determine the type of these two values ​​​​without this.

The interesting stuff starts when we get to objects (those with typeof === "object").

built-in objects work out, practically, with a bang:

  • {} —
  • date-
  • error-
  • regexp-

The only thing that drops out of the arguments list, which is either , or .
With host-objects, everything is worse again.

In IE, DOM objects began to become "normal" objects only from the 8th version, and then not quite to the end. Therefore, in IE 6-8 all these objects (HTMLCOllection, DOMElement, TextNode , as well as document and window) are simply cast to .

In all other browsers (including IE9), you can already do something with the toString result. Although everything is also not easy: HTMLCollection there , then . window - then , then , then . But you can already try to get something out of this.

It is more difficult with DOMElement: it is displayed as , a different format for each tag. But here the regular season will help us.

With other host objects (in the location and navigator tests), the story is about the same. Everywhere except IE, they can be identified by a string.

Of the minuses of using Object.prototype.toString():

1. This possibility is not consecrated by the standard. And we here should rather rejoice that everything is working so well, and not lament over some flaws.

2. Determining a type by parsing a string returned by a method that is not at all for determining the type, and even called on an object to which it does not apply, leaves some sediment on the soul.

3. In old IE, as you can see, host-objects are not normally identified.

However, it is quite a working thing when used in conjunction with other tools.


Constructors

And finally, constructors. Who better to say about the "class" of an object in JS than its constructor?

null and undefined have neither wrapper objects nor constructors.

The rest of the scalar types have wrappers, so you can get a constructor:

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

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

But instanceof will not work here:

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

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

(instanceof will work for the long-suffering new Number(5))

With functions (which are also objects), instanceof will do:

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

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

All objects of built-in classes are also easily identified by constructors: Array , Date , RegExp , Error .

One problem arises here with arguments , whose constructor is Object .

And the second with the Object itself, or rather, how to refer to it an object created through a custom constructor.

Only the base object can be defined like this:

obj instanceofObject;

As one of the definition options, iterate over all other possible types (Array , Error ...) and if none of them fall under - "object".

Constructors and host objects

Things get worse with host objects.

Let's start with the fact that IE up to the 7th version inclusive does not consider them to be normal objects at all. They simply do not have constructors and prototypes there (in any case, the programmer cannot reach them).

Things are better in other browsers. There are constructors and you can determine the value class from them. They are only called different browsers differently. For example, for an HTMLCollection the constructor will be either an HTMLCollection or a NodeList , or even a NodeListConstructor .

You should also define a base constructor for DOMElement. In FF, this is, for example, HTMLElement , from which HTMLDivElement and others already inherit.

The trick is thrown by FireFox below version 10 and Opera below version 11. There, the collection constructor is Object .

constructor.name

Constructors also have a name property that can be useful.

It contains the name of the constructor function, for example, (5).constructor.name === "Number" .

However:
1. In IE it is not at all, even in the 9th.
2. In Host-objects, browsers again mold everything that is much (and often they do not have this property at all). In Opera, DOMElement has a constructor name in general Function.prototype .
3. arguments again " object ".

conclusions

None of the presented methods gives a 100% definition of the type / class of the value in all browsers. However, together they allow you to do this.

In the near future I will try to collect all the data in tables and give an example of a defining function.

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

Table 14.5. Logical operators

Operator Description

! NOT (logical inversion)

&& AND (boolean multiplication)

|| OR (logical addition)

Table 14.6. Results of executing AND and OR operators

Operand 1

Operand 2

Table 14.7. Results of executing the NOT statement

get operator typeof

Get type operator typeof returns a string describing the data type of the operand. The operand whose type is to be found is placed after this operator and enclosed in parentheses:

s = typeof("str");

As a result of this expression, the variable s will contain the string "string" , denoting the string type.

All the values ​​that the typeof operator can return are listed in Table 1. 14.8.

Table 14.8. Values ​​returned by the typeof operator

Data type

Return string

String

Numerical

Table 14.8 (end)

Data type

Return string

Logical

Compatibility and data type conversion

It's time to consider two more important issues: data type compatibility and conversion from one type to another.

What happens when you add two numbers together? That's right - another numeric value. What if you add a number and a string? It's hard to say... Here JavaScript runs into the problem of data type incompatibility and tries to make these types compatible by converting one of them to another. It first tries to convert the string to a number and, if it succeeds, performs the addition. If unsuccessful, the number will be converted to a string and the two resulting strings will be concatenated. For example, the Web script in Listing 14-6 would convert the value of variable b when added to variable a to a numeric type; thus the variable c will contain the value 23.

Listing 14.6

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

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

d="JavaScript"; e = 2;

But since the value of the variable d cannot be converted to a number, the value of e will be converted to a string, and the result - the value of f - will become equal to

Boolean values ​​are converted to either numeric or string values, as appropriate. True will be converted to the number 1 or the string "1" , and false to 0 or "0" . Conversely, the number 1 will be converted to true and the number 0 to false . Also, false will be converted

we are null and undefined .

Part III. Web page behavior. Web scripts

It can be seen that JavaScript struggles to correctly execute even incorrectly written expressions. Sometimes it works, but more often than not, things don't work out as planned, and eventually the Web script is aborted due to an error being found in a completely different place in the script, on the absolutely correct statement. Therefore, it is better to avoid such incidents.

Operator precedence

The last issue we'll deal with here is operator precedence. As we remember, precedence affects the order in which operators in an expression are executed.

Let there be the following expression:

In this case, first the value of c will be added to the value of the variable b, and then 10 will be subtracted from the sum. The operators of this expression have the same precedence and therefore are executed strictly from left to right.

Now consider this expression:

Here, first, the value c will be multiplied by 10, and only then the value b will be added to the resulting product. The multiplication operator has higher precedence than the addition operator, so the "strictly left to right" order will be violated.

Assignment operators have the lowest precedence. That's why the expression itself is evaluated first, and then its result is assigned to a variable.

AT In general, the basic principle of executing all operators is as follows: first, operators with a higher priority are executed, and only then - operators with a lower one. Operators with the same precedence are executed in the order in which they appear (from left to right).

AT tab. 14.9 lists all the operators we have studied in descending order of their precedence.

Table 14.9. Operator precedence (in descending order)

Operators

Description

++ -- - ~ ! typeof

Increment, decrement, sign change, logical NOT, type inference

Multiplication, division, remainder

String addition and concatenation, subtraction

Comparison Operators

logical AND

Chapter 14. Introduction to Web Programming. JavaScript language

Table 14.9 (end)

Operators

Description

Logical OR

Conditional operator(see below)

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

Assignment, simple and complex

ATTENTION!

Remember this table. Incorrect order of execution of statements can cause hard-to-detect errors, in which an apparently absolutely correct expression gives an incorrect result.

But what if we need to break the normal execution order of statements? Let's use brackets. In this notation, the parenthesized statements are executed first:

a = (b + c) * 10;

Here, the values ​​of the variables b and c will be added first, and then the resulting sum will be multiplied by 10.

Operators enclosed in parentheses are also subject to precedence. Therefore, multiple nested parentheses are often used:

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

Here the statements will be executed in the following order:

1. Add b and c.

2. Multiply the resulting amount by 10.

3. Subtracting d from the product.

4. Divide the difference by 2.

5. Addition of 9 to the quotient.

If you remove the brackets:

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

then the order of execution of the operators will be as follows:

1. Multiply c and 10.

2. Divide d by 2.

3. Adding b and multiplying c and 10.

4. Subtraction from the resulting sum of the quotient from division d to 2.

5. Adding 9 to the resulting difference.

It turns out a completely different result, right?

Operator typeof returns a string indicating the type of the operand.

Syntax

The operand follows the typeof operator:

typeof operand

Options

operand is an expression representing the object or primitive whose type is to be returned.

Description

AT following table the possible return values ​​of typeof are given. Additional Information about types and primitives is on the page.

Examples

// Numbers typeof 37 === "number"; typeof 3.14 === "number"; typeof(42) === "number"; typeof Math.LN2 === "number"; typeof Infinity === "number"; typeof NaN === "number"; // even though it's "Not-A-Number" typeof Number(1) === "number"; // never use this notation! // Strings typeof "" === "string"; typeof "bla" === "string"; typeof "1" === "string"; // note that the number inside the string is still of type string typeof (typeof 1) === "string"; // typeof will always return a string in this case typeof String("abc") === "string"; // never use this notation! // Booleans typeof true === "boolean"; typeof false === "boolean"; typeof Boolean(true) === "boolean"; // never use this notation! // Symbols typeof Symbol() === "symbol" typeof Symbol("foo") === "symbol" typeof Symbol.iterator === "symbol" // Undefined typeof undefined === "undefined"; typeof declaredButUndefinedVariable === "undefined"; typeof undeclaredVariable === "undefined"; // Objects typeof(a: 1) === "object"; // use Array.isArray or Object.prototype.toString.call // to distinguish between regular objects and arrays typeof === "object"; typeof new Date() === "object"; // Anything below leads to errors and problems. Do not use! typeof new Boolean(true) === "object"; typeof new Number(1) === "object"; typeof new String("abc") === "object"; // Functions typeof function() () === "function"; typeof class C() === "function"; typeof Math.sin === "function";

null

// This has been defined since the birth of JavaScript typeof null === "object";

In the first implementation of JavaScript, values ​​were represented by a tag type and value pair. The tag type for objects was 0. null was represented as a null pointer (0x00 on most platforms). Therefore, the type of the tag for null was null, so the return value of typeof is bogus. ()

A fix has been proposed in ECMAScript (via disable) but has been rejected. This would result in typeof null === "null" .

Using the new operator

// All constructor functions created with "new" will be of type "object" var str = new String("String"); var num = new Number(100); typeofstr; // Return "object" typeof num; // Returns "object" // But there is an exception for the Function constructor var func = new Function(); typeof func; // Return "function"

Regular Expressions

Called regular expressions were a non-standard addition in some browsers.

Typeof /s/ === "function"; // Chrome 1-12 Not ECMAScript 5.1 compliant typeof /s/ === "object"; // Firefox 5+ Complies with ECMAScript 5.1

Bugs related to temporary dead zones

Prior to ECMAScript 2015, the typeof operator was guaranteed to return a string for whatever operand it was called with. This changed with the addition of non-hoisting block-scoped let and const declarations. Now, if variables are declared with let and const , and typeof is called on them in the variable declaration block, but before the declaration, then a ReferenceError is thrown. The behavior is different from undeclared variables, for which typeof will return "undefined". Block-scoped variables are in a "temporary dead zone", which lasts from the beginning of the block until the moment the variables are declared. In this zone, an attempt to access variables throws an exception.

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

Exceptions

In all current browsers there is a non-standard host object document.all , which is of type Undefined.

Typeof document.all === "undefined";

Although the specification allows custom type names for non-standard exotic objects, these names are required to be different from the predefined ones. The situation where document.all is of type undefined should be considered an exceptional violation of the rules.

Specifications

Specification Status Comments
ECMAScript Latest Draft (ECMA-262)
Draft
ECMAScript 2015 (6th Edition, ECMA-262)
Definition of "The typeof Operator" in this specification.
Standard
ECMAScript 5.1 (ECMA-262)
Definition of "The typeof Operator" in this specification.
Standard
ECMAScript 3rd Edition (ECMA-262)
Definition of "The typeof Operator" in this specification.
Standard
ECMAScript 1st Edition (ECMA-262)
Definition of "The typeof Operator" in this specification.
Standard Initial definition. Implemented in JavaScript 1.1

Browser Compatibility

Update compatibility data on GitHub

ComputersMobileserver
ChromeedgeFirefoxInternet ExplorerOperasafariandroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
typeofChrome Full Support 1 edge Full Support 12 Firefox Full Support 1 IE Full Support 3 Opera Full Support Yessafari Full Support Yeswebview android Full Support 1 Chrome Android Full Support 18 Firefox Android Full Support 4 OperaAndroid Full Support YesSafari iOS Full Support YesSamsung Internet Android Full Support 1.0 nodejs Full Support Yes

Legend

Full Support Full Support

IE-Specific Notes

In IE 6, 7, and 8, many host objects are objects, not functions. For example.

Dynamic Type Identification

Dynamic Type Identification (RTTI) allows you to determine the type of an object at runtime. It turns out to be useful for a number of reasons. In particular, by reference to the base class, you can quite accurately determine the type of the object accessible by this reference. Dynamic type identification also allows you to check in advance how successful the outcome of type casting will be, preventing an exception due to incorrect type casting. In addition, dynamic type identification is a major component of reflection.

To support dynamic type identification, C# provides three keywords a: is, as and typeof. Each of these keywords is discussed further in turn.

is operator

The specific type of an object can be determined using the is operator. Below is its general form:

expression is type

where expression denotes a single expression that describes the object whose type is being tested. If the expression is of a compatible or the same type as the type being tested, then the result of this operation is true, otherwise it is false. Thus, the result will be true if the expression is of the type being tested in one form or another. In the is operator, both types are defined as compatible if they are the same type or if reference conversion, boxing, or unboxing is provided.

The following is an example of using the is operator:

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("Variable a is of type Add"); if (s is Sum) Console.WriteLine("The type of variable s is inherited from class Add"); Console.ReadLine(); ) ) )

as operator

Sometimes a type conversion needs to be done at run time, but not to throw an exception if the conversion fails, which is quite possible with a type cast. The as operator serves this purpose, and has the following general form:

expression as type

where expression denotes a single expression that is convertible to the specified type.

If the outcome of such a conversion is successful, then a reference to the type is returned, otherwise, a null reference. The as operator can only be used for reference conversion, identity, boxing, unboxing. In some cases, the as operator can be a convenient alternative to the is operator. As an example, consider the following program:

Using System; namespace ConsoleApplication1 ( class Add ( ) class Sum: Add ( ) class Program ( static void Main() ( Add a = new Add(); Sum s = new Sum(); // Perform cast a = s as Add; if (a != null) Console.WriteLine("Conversion succeeded"); else Console.WriteLine("Error while converting"); Console.ReadLine(); ) ) )

The result of executing this program will be a successful conversion.

JavaScript or JS(shortly) not an easy language and novice developers will not learn about it right away. At first they learn the basics and everything seems colorful and beautiful. Going a little deeper, there are JavaScript arrays, objects, callbacks and everything else that often blows the mind.

In JavaScript, it's important to check the type of a variable correctly. Let's say you want to know if a variable is an array or an object? How to check it correctly? In this particular case, there are tricks during the verification and that's what this post will be about. Let's get started right away.

Checking the type of a variable

For example, you need to check if a variable is an object, an array, a string, or a number. You can use typeof for this, but it won't always tell you the truth, and I'll show you why in the example below.

I wrote this example to illustrate why typeof is not always the right choice.

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

Result of code execution:

String number object object

Right? - Of course not. There are two problems. Each of them will be described in detail and a solution proposed.

First problem: float number, output as number

Comparison.float is not a number and must be a float instead of number. To fix this, you can create a function with a check like in the code below.

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; )

The isFloat() function checks all values ​​for floating point numbers. First check if the variable is equal n number (Number(n) === n) and if yes, then one more check is made for division with a remainder and if there is a remainder, then a boolean is returned ( true or false) result (n % 1 !== 0).

In the example above, it returns true, false and false. The first meaning is float type, the second is not - this is a regular number and the last is just an empty string that does not fit the rules.

Second problem: the array was defined as an object

In the very first example, the array is rendered as an object, which is not very good, because sometimes you need to use this type and nothing else.

There are several ways to test a variable for an array type.

The first option (good option). Check if data belongs to an array using instanceof().

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

The second option (good option). The Array.isArray() method returns a boolean value that will depend on whether the variable is an array or not ().

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

The third option (the best, but long). For convenience, you can make this method a function. Using Object we make . If the result of Object.prototype.toString.call(data) is not equal, then the variable is not an array ().

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

The last result as a convenience function:

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

Now you can call the isArray() functions and set an array or something as an argument and see the result.

Afterword

The record turned out to be quite large than it was originally intended. But I'm happy with it because it's concise and clear enough to describe the difficulties of validating variables in JavaScript and how to get around them.

If you have any questions, please post them below this post. I'll be happy to help.

Internet