This article introduces variables and types in JavaScript in detail from basic principles to practical applications.
First, JavaScript data types
The ECMAScript standard specifies seven data types, which it divides into two types: base and reference data types
The base type
String
A sequence of characters representing a text valueNumber
Integer floating point numberBoolean
Contains two valuestrue
.false
Undefined
Contains only one value:undefined
Null
Contains only one value:null
Symbol
A unique data type that cannot be changed
BigInt (a seventh primitive type BigInt has been added to ES10 and is now supported by the latest Chrome)
Reference types
object
(In JS everything except basic data types are objects. Data are objects, functions are objects, and regular expressions are objects.)
The difference between base types and reference types
Reference stack and heap memory explain the difference between base and reference types
Null and undefined
In the base type, there are two types Null and Undefined. They both have one and only one value, Null and Undefined, and they both represent nothing and Null. I usually distinguish them as follows:
null
An object is intentionally assigned to null to indicate that it is empty and has no value.
So it is normal for an attribute of an object to have a value of NULL, which is zero when converted to a value.
undefined
Represents “missing value”, that is, there should be a value here, but it is not defined yet,
Undefined NaN when converted to a value (a special value for a non-numeric value)
4. Symbol type
The Symbol type is a new base type added to ES6.
Each Symbol value returned from Symbol() is unique. A symbol value can be used as an identifier for object properties; This is the only purpose of this data type.
Application scenarios
See Action on Scene > Handwriting Call function
Number type
5.1 Precision Loss
Inaccurate decimals, such as 0.1+0.2! = = 0.3
All the data in the computer is stored in binary, so the computer first converts the data into binary for calculation, and then converts the calculation result into decimal.
In the calculation of 0.1+0.2, the accuracy of binary calculation was lost, resulting in the re-conversion to decimal does not match the expected result.
5.2 the IEEE 754
The IEEE754 standard contains a binary representation of a set of real numbers. It has three parts:
- The sign bit
- Index a
- Mantissa bits
The three precision floating point numbers are as follows:
JavaScript
The 64-bit double precision floating-point encoding is used, so itsThe sign bit
Account for1
Bit, exponent bit11
Digit, mantissa digit52
position
Now let’s understand what is the sign bit, the exponential bit and the mantissa bit, taking 0.1 as an example:
Its binary is: 0.0001100110011001100…
To save storage space, in computers it is expressed in scientific notation, i.e
1.100110011001100...
X 2-4
If this is confusing, think of a decimal number:
The scientific notation for 1100 is 11 X 102
So:
The sign bit is to identify the positive and negative, 1 represents negative, 0 represents positive;
Index bits The index of the storage science counting method;
The mantissa digit stores the significant digit after scientific counting;
So what we usually see as binary is actually the mantissa that the computer actually stores.
5.3 Maximum number that JavaScript can represent
Limited by the IEEE 754 double precision 64-bit specification:
Maximum number represented by exponential potential energy: 1023(decimal)
The maximum mantissa digit that can be expressed is the case where all the mantissa digits are 1
So the largest number that JavaScript can represent is bits
1.111… X 21023 = 1.7976931348623157e+308 in decimal form.
5.4 Maximum security number
MAX_SAFE_INTEGER specifies the maximum safe Number, which is 9007199254740991. There is no loss of precision (except for decimals) within this Number, which is actually 1.111… X 252.
We can also use open source libraries to handle large integers:
- node-bignum
- node-bigint
The bigInt type was introduced in ES10 and is now available in Chrome. You can use bigInt to manipulate numbers that exceed the maximum safe number.
Other reference types
In ECMAScript’s definition of types, only the Object type is given. In fact, many of the variables we use to refer to types are not constructed by Object, but their prototype chain ends in Object, and these types are reference types.
Array
An array ofDate
The date ofRegExp
regularFunction
function
Packing and unpacking
- Boxing conversion: Converts the base type to the corresponding packaging type
- Unboxing: Converts a reference type to a primitive type
Since primitive types cannot extend properties and methods, how do we call methods using primitive types?
Whenever we operate on an underlying type, an object wrapped around the type is automatically created in the background, allowing us to call some methods and properties, such as the following code:
var name = "msd";
var name2 = name.substring(2);
Copy the code
In fact, the following processes occur:
- To create a
String
Is an instance of a wrapper type - Called on an instance
substring
methods - Destroy instance
That is, when we call a method with a primitive type, we automatically box and unbox it, just as when we call a method with a Number or Boolean type.
The conversion from a reference type to a basic type — that is, the unpacking — follows the toPrimitive rules of the ECMAScript specification. It usually calls the valueOf and toString methods of the reference type. You can also override the TopeimPron method directly. Conversion to different types of values generally follows different principles, such as:
- The reference type is converted to
Number
Type, called firstvalueOf
Call again,toString
- The reference type is converted to
String
Type, called firsttoString
Call again,valueOf
If neither valueOf nor toString exists, or if no primitive type is returned, TypeError is raised.
const obj = {
valueOf: () = > { console.log('valueOf'); return 123; },
toString: () = > { console.log('toString'); return 'ConardLi'; }};console.log(obj - 1); // valueOf 122
console.log(`${obj}ConardLi`); // toString ConardLiConardLi
const obj2 = {
[Symbol.toPrimitive]: () = > { console.log('toPrimitive'); return 123; }};console.log(obj2 - 1); // valueOf 122
const obj3 = {
valueOf: () = > { console.log('valueOf'); return {}; },
toString: () = > { console.log('toString'); return{}; }};console.log(obj3 - 1);
// valueOf
// toString
// TypeErrorCopy the codeCopy the code
In addition to automatic unpacking and automatic packing in the program, we can also carry out manual unpacking and packing operations. We can call valueOf or toString of wrapper type directly to implement unpacking operation:
var num =new Number("123");
console.log( typeof num.valueOf() ); //number
console.log( typeof num.toString() ); //string
Copy the code
Type conversion
Because JavaScript is a weakly typed language, type conversions happen very frequently, and the boxing and unboxing mentioned above is actually a type conversion.
There are two types of type conversions. Implicit conversions are the type conversions that are performed automatically by programs, and cast conversions are the type conversions that are performed manually.
Without mentioning casts here, let’s take a look at a few situations where implicit casts can be a headache, and how to do them:
7.1 Type Conversion Rules
If implicit conversions occur, the following rules apply:
7.2 If Statements and logical Statements
In if statements and logical statements, if there is only a single variable, the variable is first converted to Boolean. Only the following cases are converted to false, and the rest are converted to true:
Null undefined '' NaN 0 false Copy codeCopy the code
7.3 Various operational mathematical operators
When we apply the mathematical operator (- * /) to various non-number types, we first convert non-number types to Number types;
1 -true // 0 1-null // 1 1 * undefined // NaN 2 * ['5'] // 10 Copy codeCopy the code
Note that + is an exception, when the + operator is executed:
- 1. When one side is
String
Type that is recognized as string concatenation and will preferentially convert the other side to string type. - 2. When one side is
Number
Type, the other side is the original type, the original type is converted toNumber
Type. - 3. When one side is
Number
Type, on the other side is the reference type, which references the type andNumber
Type to string concatenation.
123 + '123' // 123123 (Rule 1) 123 + NULL // 123 (Rule 2) 123 + true // 124 (Rule 2) 123 + {} // 123[object object] (Rule 3) Copy the codeCopy the code
7.4 = =
When == is used, if both sides of the type are the same, then the comparison result is the same as ===, otherwise an implicit conversion will occur. The conversion that occurs when == is used can be divided into several different cases (only the two sides of the type are considered) :
- 1.NaN
NaN always returns false when compared to any other type (including himself).
NaN == NaN // false Copies the codeCopy the code
- 2.Boolean
Boolean is first converted to the Number type in comparison to any other type.
True == 1 // true true == '2' // false true == ['1'] // true true == ['2'] // false Copies the codeCopy the code
Undefined, null, and Boolean are compared. Although undefined, null, and false can be easily imagined to be false, they compare to false because false is first converted to 0:
Undefined == false // false null == false // false Copy codeCopy the code
- 3. The String and Number
Compare String and Number. First, convert String to Number.
123 == '123' // true '== 0 // true copies the codeCopy the code
- 4. A null, and undefined
Null == undefined the comparison result is true. Otherwise, the comparison value of null, undefined, and any other result is false.
null == undefined // true null == '' // false null == 0 // false null == false // false undefined == '' // false Undefined == 0 // false undefined == false // false Copies the codeCopy the code
- 5. Primitive and reference types
When the original type and reference type are compared, the object type is converted to the original type according to ToPrimitive rules:
'[object object]' = = {} / / true '1, 2, 3 = = [1, 2, 3] / / true copy codeCopy the code
Consider the following comparison:
[] = =! [] // true copies the codeCopy the code
! The priority of the ==,! [] is first converted to false, and then, according to the second point above, false is converted to Number type 0, and left [] is converted to 0, which is more or less equal to both sides.
[null] == false // true [undefined] == false // true Copy codeCopy the code
According to the ToPrimitive rules for arrays, when an array element is null or undefined, the element is treated as an empty string, so both [null] and [undefined] are converted to 0.
So, having said that, it’s recommended to use === to determine if two values are equal…
An interview question is attached
const a = {
num: 0.valueOf: function() {
return this.num += 1}};const equality = (a==1 && a==2 && a==3);
const b = { value: [3.2.1].valueOf: function () {return this.value.pop(); }}
Copy the code
How to determine JavaScript data types
8.1 typeof
Applicable scenario
The typeof operator can determine exactly whether a variable is of any of the following primitive types:
typeof 'ConardLi' // string typeof 123 // number typeof true // boolean typeof Symbol() // symbol typeof undefined // Undefined copy codeCopy the code
You can also use it to determine the type of function:
Typeof function(){} // function copies codeCopy the code
Not applicable Scenario
When you use typeof to determine reference types it seems a bit weak:
typeof [] // object typeof {} // object typeof new Date() // object typeof /^\d*$/; // object copies the codeCopy the code
All reference types except functions are judged to be object.
Typeof NULL === ‘object’ also causes headaches. This is a bug that has been around since the first version of JavaScript, and has not been fixed since it caused a lot of compatibility issues…
8.2 instanceof
The instanceof operator helps us determine what type of object the reference type is:
[] instanceof Array // true new Date() instanceof Date // true new RegExp() instanceof RegExp // true copy codeCopy the code
Let’s review a few rules of the prototype chain:
- 1. All reference types have object properties, that is, they are free to extend properties
- 2. All reference types have one
__proto__
(Implicit stereotype) property, which is a normal object - 3. All functions have
prototype
(Explicit stereotype) property, which is also a normal object - 4. All reference types
__proto__
The value refers to its constructorprototype
- 5. When trying to get a property of an object, if the variable itself does not have the property, it is destroyed
__proto__
To look for in
[] instanceof Array determines whether array. prototype is on the prototype chain of [].
So using Instanceof to detect data types is not very accurate, which is not what it was designed for:
[] instanceof Object // true function(){} instanceof Object // trueCopy the code
Also, instanceof doesn’t detect basic data types, so instanceof isn’t a good choice.
See the handwriting instanceof function
reference
Juejin. Cn/post / 684490…