📜 ⬆️ ⬇️

"It is difficult about the simple." JS data types. In search of the truth of primitives and objects

I decided to write a series of articles entitled “Difficult about simple.” This cycle will be dedicated to the JavaScript language. Why is "difficult about the simple"? Because everything that I will be telling, I will be telling, taking into account the peculiarities of the interpreter, starting with data types. All this will be done in order to be able to tell just about the complex, for example, about the methods of inheritance in JavaScript and other patterns.

JavaScript is an object-oriented programming language with prototype organization.
What does it mean “with the prototype organization”, we will talk in the next article (it will definitely be), but why it is “object-oriented” and whether everything is in the JS object, we will find out today.
To fulfill its goals JSʻu enough only 9 types. Moreover, only 6 of them are available to the program, the remaining 3 are available only at the implementation level and are used by the specification. At first glance (and this is the first misconception), everything in JS is an object. So, five of the six types available to the program are so-called primitives and are not objects (below I will explain why and how they are confused with objects). These five primitives are:

- String (s = 'str')
- Number (n = 10)
- Boolean (b = true)
And as I call them "philosophical types":
- null (v = null)
- undefined (u = undefined)

Philosophical by the fact that null means that nothing is assigned to a variable, and undefined means that a variable has been assigned a void. What is the difference between “nothing” and “emptiness” in this case - think it over at your leisure. Now we will not do this.
')
The sixth type (object) available to the program is:
- Object (not to be confused with the Object constructor, we are now talking only about abstract types!) - the only type representing objects in JavaScript.
An object is a data structure (a whole set of them), represented as a set of key-value pairs. The value can be any of the data types - then it will be a property of the object, or even a function - then it will be a method of the object.

There are a great many ways to work with primitives. Starting with the fact that they can be assigned to variables through literals or through constructors and ending with the fact that primitives can not be declared into variables at all, working with them directly. Also, primitives can be in global variables and local ones.

Here are some examples:

var v1; //undefined ()   var v2='2'; //    var v3 = new String(2); // ,    .     String v4 = String(2); //     .   window.v4 '2'.length; //            34..toString(); //           12. toString(); //           (22).toString();//           


In the last 4 commands, you can clearly see how a primitive is confused with an object - after all, we call the method, through the point, just like an object. Indeed, it seems that these primitives are objects.

Fallacy is compounded when we check the type of a variable, for example

 var v = null; typeof v; 


and get in response to "object".

And if we write:
 var v = null; v instanceof Object; 


Then porridge will appear in the head, because the result of the last line will be “false”. That is, the variable v has the type object, but is not inherited from the type Object. What the heck?!

To begin with I will explain a dirty trick with typeof null. This operator returns the type of the object. The fact is that the typeof operator returns a string value taken from a rigidly fixed table, where it is written: “for null, return“ object ””. The instanceof operator - checks whether something belongs to the specified data type. How he does it, I will tell in the next article, but I assure you that in this case he worked correctly, the primitive null is by no means inherited from the Object type - it is in itself, the primitive is the lowest stage of development.

Okay, with typeof and instanceof figured out, but methods are called by primitives - like objects are straight! How, if it is not an object?

This is what it is. There is such a thing as wrapper functions (constructors) (and again everything will be clarified in the second article). They are for all primitives (Number (), Boolean (), String ()), as well as others. Their essence consists in creating an object from a primitive that will have auxiliary methods for working with this type of primitive.
For example, you can create a variable like this:

 Var num = new Number(23.456); 


In this case, from the primitive 23.456 we get the object.
For the number type, the Number () constructor has an auxiliary method toPrecision () - it determines the number of significant digits for the number. For example, if the number 23.456 is set the number of significant digits 4, then we will get the number 23.45.
And so when we try to address the primitive as an object:

 (23.456). toPrecision(4); 


The interpreter is temporarily wrapped, primitive to an object by calling new Number (23.456), and then this object calls the method toPrecision (), which it now has. Thus, many mistakenly believe that everything in JS is an object.

There is also another example of misleading and misunderstanding of what is happening. Here is the code:

 var str = 'str'; str.test = 'test'; //  ,   ,  console.log(str.test); //undefined 


If we thought, as before, that str is an object, we would be surprised why he did not remember the new test property in himself. But now we know that when the primitive is referred to as an object, it temporarily turns into an object of type String. But after performing the operation, this wrapper disappears, and with it the new test property. That's all, no magic.

Actually, running ahead, while wrapping a primitive into an object, a whole chain of inheritance is built (as organized, we will talk later), but in fact it turns out that this is the “matryoshka”:

Object (Number (<primitive>)). The parent of any object in JS, anyway, is Object. When you call a property in an object, the search passes through this whole “matryoshka” until it finds this property in one of the objects or returns undefined or if you looked for a method, it will throw an exception. Thus, the properties of the Object are also available for the primitive. How prototype inheritance works and we will talk about its intricacies in the second article.

For intrigue over the second article, which I want to release, I'll tell you about one more thing related to the functions of the designers - this is a type conversion. JS is not a strongly typed language. This means that at the time of declaration of a variable, we are not obliged to indicate what type it is, and moreover, during the program operation, data of absolute any type can be put into this variable. And also we can use, for example, string variables in mathematical operations or vice versa, numbers in a concatenation operation. Example:

 var str = 'abc'; str+1; // 'abc1' 


Here, a primitive of type number - 1 will be converted to a string primitive. In objects, this feature is available through a call to the toString () method, in objects of type number, there is a valueOf () method that returns a primitive of type number. But we sort of said that only objects can have methods. So in the process of converting a primitive from one type to another, does it also turn into an object? I assure you that no. The call to this method occurs implicitly when the constructor function is called by the interpreter without the new operator. What a magic new operator and what happens when a constructor function is called without it, and what a pancake at the end of a constructor function like that, we'll talk in the next article. For now, take my word for it - type conversion occurs right away - from a primitive to a primitive.

So far, of course, there are more questions than answers, but believe me, everything will become much more transparent after reading the second article. Here I mostly intrigued and raised a number of questions - so to speak, stirred minds. But still something can be learned from this article:
1. Despite the conventional wisdom, “everything in JS is an object” is not so, we found out that out of 6 data types available to the programmer, as many as 5 are primitives and only one represents the type of objects.
2. About objects, we learned that this is a data structure that contains key-value pairs. When the value can be any of the data types (and it will be a property of the object) or a function (and it will be a method of the object).
3. But the primitives are not objects. Although it is possible to work with them as with an object (and this causes a delusion that the primitive is an object), but ...
4. Variables can be declared both by simple (literally) (var a = 'str'), and through the constructor function (wrapper) (var a = new String ('str')). In the second case, we get no longer a primitive, but an object created by the wrapper function String (). (what kind of magic operator is new and what is a constructor function we will find out further).
5. We learned that it is through the creation of a wrapper on a primitive (new String ('str')) that you can work with as an object. It is this wrapper that the interpreter creates around the primitive when we try to work with it as an object, but after performing the operation it collapses (therefore, the primitive can never remember the property that we assign to it a.test = 'test'- the test property will disappear with the wrapper ).
6. We learned that objects have a toString () method that returns a string representation of the object (for the type number, valueOf () will return a numeric value).
7. They understood that when performing concatenation operations or mathematical operations, primitives can redefine their type into the necessary one. To do this, they use the wrapper function of their types, but without the operator new (str = String (str)). (What is the difference and how it works, let's talk further)
8. And finally, we learned that typeof takes values ​​from a hard-coded table (this is where another misconception comes from, based on typeof null // object).

Source: https://habr.com/ru/post/150730/


All Articles