Contacts

The getter of type typeof. JavaScript, typeof, types and Javascript classes check variable type

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 variety of reasons. In particular, by reference to the base class, you can fairly accurately determine the type of object available from this link. Dynamic type identification also allows you to check in advance how successful the typecast will be, preventing exceptional situation due to incorrect type conversion. 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 below in turn.

Is operator

The specific type of an object can be determined using the is operator. Its general form is shown below:

expression is type

where expression denotes a separate expression describing the object whose type is being checked. If the expression is of a compatible type or of the same type as the type being tested, then the result of this operation is true, otherwise it is false. Thus, the result is true if the expression has a testable type in one form or another. The is operator defines both types to be compatible if they are of the same type, or if reference conversion, boxing, or unboxing is provided.

Below 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 s is inherited from the Add class "); Console.ReadLine ();)))

As operator

Sometimes the type conversion needs to be done at runtime, but not throw an exception if the conversion fails, which is quite possible with type casting. For this purpose, the as operator serves, which has the following general form:

expression as type

where expression denotes a single expression to be converted to the specified type.

If this conversion succeeds, then a reference to the type is returned; otherwise, an empty reference. The as operator can only be used for reference conversion, identity, boxing, unboxing. In some cases, the as operator can serve as 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 typecasting a = s as Add; if (a! = null) Console.WriteLine ("Conversion was successful"); else Console.WriteLine ("Conversion failed"); Console.ReadLine ();)))

The result of this program will be a successful conversion.

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

Table 14.5. Logical operators

Operator Description

! NOT (logical inversion)

&& AND (logical multiplication)

|| OR (logical addition)

Table 14.6. Results of executing AND and OR operators

Operand 1

Operand 2

Table 14.7. Results of the NOT statement

Get operator typeof

Get Type Operator typeof returns a string describing the data type of the operand. The operand whose type you want to know is placed after this operator and enclosed in parentheses:

s = typeof ("str");

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

All values ​​that can return typeof operator are listed in table. 14.8.

Table 14.8. Values ​​returned by the typeof operator

Data type

Returned string

String

Numerical

Table 14.8 (end)

Data type

Returned string

Logical

Data type compatibility and conversion

Now is the 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 - one more thing numerical value... And if you add a number and a string? It's hard to say ... Here JavaScript is faced with the problem of incompatibility of data types 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 successful, performs the addition. If unsuccessful, the number will be converted to a string and the two resulting strings will be concatenated. For example, executing the Web script in Listing 14.6 will convert the value of b to a numeric type when added to a; 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 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

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 will be converted to 0 or "0". Conversely, the number 1 will be converted to true, and the number 0 will be converted to false. Also, false will be converted

the values ​​are null and undefined.

Part III. Behavior of web pages. Web scripts

It can be seen that JavaScript is struggling to correctly execute even the incorrectly written expressions. Sometimes it works, but more often everything does not work as planned, and, in the end, the execution of the Web script is interrupted due to the discovery of an error in a completely different place, on the absolutely correct operator. Therefore, it is better not to allow such incidents.

Operator priority

The last issue we will look at here is operator precedence. As we recall, precedence affects the order in which statements are executed in an expression.

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 priority and therefore are executed strictly from left to right.

Now, consider an expression like this:

Here, first, the value of c will be multiplied by 10, and only then the value b will be added to the resulting product. The multiplication operator takes precedence over the addition operator, so strict left-to-right ordering will be out of order.

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

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

V tab. 14.9 lists all the operators we studied in descending order of their priority.

Table 14.9. Operator precedence (descending order)

Operators

Description

++ - - ~! typeof

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

Multiplication, division, taking the remainder

Addition and concatenation of strings, 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 statement execution order can lead to hard-to-detect errors, in which a seemingly absolutely correct expression gives the wrong result.

But what if we need to break the normal order of execution of statements? Let's use parentheses. With this notation, statements enclosed in parentheses are executed first:

a = (b + c) * 10;

Here, the addition of the values ​​of the variables b and c will be performed 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 sequence:

1. Addition b and c.

2. Multiply the resulting amount by 10.

3. Subtracting d from the product.

4. Dividing the difference by 2.

5. Add 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. Multiplication of c and 10.

2. Dividing d by 2.

3. Addition b and products c and 10.

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

5. Adding 9 to the resulting difference.

The result is completely different, isn't it?

JavaScript or Js(abbreviated) is not a simple language and novice developers do not immediately learn about it. At first they learn the basics and everything seems colorful and beautiful. Going a little deeper, there appear JavaScript arrays, objects, callbacks and the like that the brain often takes out.

In JavaScript, it is 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 check and that is what this entry 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, array, string or number. You can use typeof for this, but it will not always give you the truth, and in the example below I will show why.

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 object keys var _objKeys = Object.keys (_comparison); for (var i = 0; i<= _objKeys.length - 1; i++) { // выведем в консоль тип каждой переменной console.log(typeof _comparson[_objKeys[i]]); }

The result of executing the code:

String number number object object

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

First problem: float number, output as number

Comparison.float is not a number and should be a float instead of number. To fix this, you can create a function with validation as 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, it checks if the variable is equal to n number (Number (n) === n) and if so, another check is done for division with remainder, and if there is a remainder, then a boolean ( 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 an ordinary 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 was displayed as an object and this is not very good, because sometimes you need to use this particular type and nothing else.

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

First option (good option). We check if data belongs to an array using instanceof ().

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

Second option (good option). The Array.isArray () method returns a boolean value, which 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 longest). For convenience, you can make this a function. Using Object, we do. 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 () function and set an array or something else as an argument and see the result.

Afterword

The recording turned out to be rather large than it was originally intended. But I'm happy with it, because it briefly and clearly describes the difficulties in checking variables in JavaScript and how to get around them.

If you still have any questions - write them below to this entry. I will be happy to help.

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

The following notes should be added to this table:

1. typeof null === "object".

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

In practice, this is inconvenient in JavaScript. So the ES 5.1 developers are going to do a more intuitive thing: typeof null === "null".

But since we have ES3 so far, make no mistake, for example, on this:

/ * The 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 actually find the object (FAIL) obj.method ();)

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

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

Don't be surprised that Safari stubbornly thinks HTMLCollection is a function type, and IE before version 9 kept our favorite alert () function as an object. Also Chrome used to think of RegExp as function, but now it seems to have sensed and respond to it with 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 debug information, but the type of a variable cannot be determined by it.

Object.prototype.toString ()

Although toString is redefined within 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.

The method fails on null and undefined. Different browsers return, sometimes expected, and sometimes in general. However, it is easy to determine the type of these two values ​​without it.

The fun begins 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 falls out of the list of arguments is that, then.
With host objects, things are getting 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, and along with document and window) are converted to simply.

In all other browsers (including IE9), you can already do something with the result of toString. Although everything is also not easy: HTMLCollection is 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, - its own format for each tag. But here, the regular season will help us.

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

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

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

2. Determination of the type by parsing the string returned by a method that is not at all for determining the type, and is also called on an object to which it does not belong, leaves some residue on the soul.

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

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


Constructors

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

Null and undefined have neither wrapper objects nor constructors.

The rest of the scalar types have wrappers, respectively, 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 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 will work for the long-suffering new Number (5))

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

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 their 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 this way:

obj instanceof Object;

As one of the variants of the definition - to iterate over all other possible types (Array, Error ...) and if none matches - "object".

Constructors and host objects

With host objects, things are getting worse.

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

Other browsers do better. There are constructors and you can use them to determine the value class. Only they are called differently in different browsers. For example, for HTMLCollection, the constructor will be either HTMLCollection or NodeList, or even NodeListConstructor.

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

FireFox below the 10th version and Opera below 11. The collection constructor is there - 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".

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

conclusions

None of the presented methods provide one hundred percent 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.



Did you like the article? Share it