Introduction
Variables and types are learningJavaScript
The first thing you come into contact with, but often the simplest thing still hides a lot of knowledge you don’t know or are prone to make mistakes, such as the following questions:
-
JavaScript
What is the specific storage form of variables in memory? -
0.1+0.2
Why not equal to0.3
? What are the specific reasons for decimal calculation errors? -
Symbol
What are the characteristics and actual application scenarios of? -
[] == ! []
、[undefined] == false
Why is it equal totrue
? When will implicit type conversion occur in the code? What are the rules for conversion? - How to judge the type of variable accurately?
If you can’t answer the above questions well, that means you haven’t fully mastered this part of knowledge, then please read the following articles carefully.
This paper introduces in detail from the basic principle to practical application.JavaScript
Knowledge of variables and types in.
I JavaScript data types
ECMAScript standardSpecified7
A data type that combines this7
There are two types of data: primitive type and object type.
initial form
-
Null
: contains only one value:null
-
Undefined
: contains only one value:undefined
-
Boolean
: contains two values:true
Andfalse
-
Number
: integer or floating point number, and some special values (-Infinity
、+Infinity
、NaN
) -
String
: a string of characters representing text values -
Symbol
: An instance is a unique and unchangeable data type
(ates10
The seventh primitive type has been added toBigInt
, has now been updatedChrome
Support)
object type
-
Object
It is not too much to divide yourself into categories, except for the common ones.Object
,Array
、Function
Such as belong to special objects
Second, why distinguish between the original type and the object type
2.1 immutability
The original types mentioned above are found inECMAScript
In the standard, they are defined asprimitive values
, that is, the original value, represents that the value itself cannot be changed.
Take a string as an example. When we call methods that manipulate strings, no method can directly change the string:
var str = 'ConardLi';
str.slice(1);
str.substr(1);
str.trim(1);
str.toLowerCase(1);
str[0] = 1;
console.log(str); // ConardLi
In the above code, we are rightstr
Several methods were called, without exception. These methods all generated a new string based on the original string instead of directly changing it.str
This proves the immutability of strings.
So, when we continue to call the following code:
str += '6'
console.log(str); // ConardLi6
You will find that,str
The value of the has been changed, which makes the character string immutable. In fact, it is not, we understand from memory:
InJavaScript
In, each variable needs a space to store in memory.
Memory space is divided into two types, stack memory and heap memory.
Stack memory:
- The stored value is fixed in size
- Less space
- The stored variables can be directly operated, and the operation efficiency is high
- The storage space is automatically allocated by the system
JavaScript
The value of the original type in is stored directly in the stack, which allocates memory space for variables when they are defined.
Since the size of the memory space in the stack is fixed, the variables stored in the stack are doomed to be immutable.
In the above code, we executedstr += '6'
The operation of the, in fact, is in the stack and opened up a piece of memory space for storage'ConardLi6'
, and then the variablestr
Point to this space, so it does not violateImmutable
Characteristics.
2.2 Reference Type
Heap memory:
- The stored value is variable in size and can be adjusted dynamically.
- Large space and low operating efficiency
- Unable to directly operate its internal storage, read with reference address
- Allocate space by code
Compared with the original type with immutability above, I am used to calling the object a reference type. The value of the reference type is actually stored in the heap memory. It only stores a fixed-length address in the stack, which points to the value in the heap memory.
var obj1 = {name:"ConardLi"}
var obj2 = {age:18}
var obj3 = function(){...}
var obj4 = [1,2,3,4,5,6,7,8,9]
Since memory is limited, these variables cannot occupy resources in memory all the time, so this article is recommended here.Garbage Collection and Memory Leakage in JavaScriptHere I tell you
JavaScript
How to recycle garbage and some scenarios where memory leaks may occur.
Of course, reference types no longer haveImmutability
, we can easily change them:
obj1.name = "ConardLi6";
obj2.age = 19;
obj4.length = 0;
console.log(obj1); //{name:"ConardLi6"}
console.log(obj2); // {age:19}
console.log(obj4); // []
Take an array as an example, many of its methods can change itself.
-
pop()
Delete the last element of the array. If the array is empty, it will not change the array, return undefined, change the original array, and return the deleted element. -
push()
Add one or more elements to the end of the array, change the original array, and return the length of the new array. -
shift()
The first element of the array is deleted, if the array is empty, no operation is performed, undefined is returned, the original array is changed, and the value of the first element is returned -
unshift()
Add one or more elements to the beginning of the array, change the original array, and return the length of the new array. -
reverse()
Reverses the order of elements in the array, changes the original array, and returns the array -
sort()
Sorting the array elements, changing the original array, and returning the array -
splice()
Add/delete items from the array, change the original array, and return the deleted elements.
Let’s compare the difference between the original type and the reference type through several operations:
2.3 replication
When we copy the value of one variable to another variable, the original type and the reference type behave differently. Let’s look at the original type first:
var name = 'ConardLi';
var name2 = name;
Name2 = 'code secret garden';
console.log(name); // ConardLi;
There is a variable in memoryname
, the value isConardLi
. We start with variablesname
Copy a variablename2
At this time, a block of new space is created in memory for storageConardLi
Although the two values are the same, the memory space they point to is completely different and the two variables do not affect each other in any operation.
Copy a reference type:
var obj = {name:'ConardLi'};
var obj2 = obj;
Obj2.name = 'code secret garden';
console.log(obj.name); // code Secret Garden
When we copy variables of reference type, we actually copy the addresses stored in the stack, so we copy them out.obj2
In fact andobj
Pointed to the same object in the heap. Therefore, if we change the value of any one variable, the other variable will be affected, which is why there are deep copies and shallow copies.
2.4 comparison
When we compare two variables, the performance of different types of variables is different:
var name = 'ConardLi';
var name2 = 'ConardLi';
console.log(name === name2); // true
var obj = {name:'ConardLi'};
var obj2 = {name:'ConardLi'};
console.log(obj === obj2); // false
For the original types, their values are directly compared during comparison, or returned if the values are equal.true
.
For reference types, their reference addresses are compared during comparison. Although the objects stored in the heap of the two variables have the same attribute values, they are stored in different storage spaces, so the comparison value isfalse
.
2.5 Value Delivery and Reference Delivery
With the following example, let’s first take a look at what is value passing and what is reference passing:
let name = 'ConardLi';
function changeValue(name){
Name = 'code Secret Garden';
}
changeValue(name);
console.log(name);
Execute the above code, if the final printedname
Yes'ConardLi'
, there is no change, indicating that the function parameter passes the value of the variable, that is, the value pass. If the final print isCode secret garden
, the operation inside the function can change the passed variable, then the function parameter is passed by reference, that is, reference passing.
Obviously, the above implementation result is'ConardLi'
In other words, the function parameter is only a local variable copied from the incoming variable. Changing this local variable will not affect the external variable.
let obj = {name:'ConardLi'};
function changeValue(obj){
Obj.name = 'code secret garden';
}
changeValue(obj);
console.log(obj.name); // code Secret Garden
The above code may make you wonder, is the parameter a reference type or a reference pass?
First of all, let’s be clear.ECMAScript
Parameters of all functions in are passed by value.
Similarly, when the function parameter is a reference type, we also copy a copy of the parameter to the local variable, but the copy is only pointing to the address in the heap memory. We operate on the attribute of the object inside the function, which is actually the same as the value in the heap memory pointed to by the external variable, but this does not represent reference transfer. Let’s take another example:
let obj = {};
function changeValue(obj){
obj.name = 'ConardLi';
Obj = {name:'code secret garden'};
}
changeValue(obj);
console.log(obj.name); // ConardLi
It can be seen that function parameters do not pass variablesQuote
, but a copy of the variable. When the variable is of the original type, this copy is the value itself. When the variable is of the reference type, this copy is the address pointing to the heap memory. So, remember again:
ECMAScript
Parameters of all functions in are passed by value.
Iii. indistinguishable null and undefined
In the original type, there are two typesNull
AndUndefined
, they all have and have only one value,null
Andundefined
, and they all represent no and empty, I generally distinguish them like this:
null
Represents an assigned object and deliberately assigns an object tonull
, deliberately indicating that it is empty and should not have a value.
Therefore, an attribute value of the object isnull
Is normal,null
When converted to a numeric value, the value is0
.
undefined
“Missing Value” means there should be a value here, but it has not been defined yet.
If an object has an attribute value ofundefined
, this is not normal, such asobj.name=undefined
, we should not write like this, should be directlydelete obj.name
.
undefined
When converted to a numerical valueNaN
(Special value of non-numeric value)
JavaScript
Is a dynamic type language, members may not exist at all (because the existence is only known at runtime) except for the null value indicating existence. This isundefined
What’s the point? ForJAVA
This strongly typed language, if any"undefined"
In this case, the compilation will fail directly, so it does not need such a type.
Four, not familiar Symbol type
Symbol
Type isES6
An original type newly added in.
Each Symbol value returned from symbol () is unique. A symbol value can be used as an identifier of an object attribute; This is the only purpose of this data type.
Let’s take a lookSymbol
What are the characteristics of the type?
4.1 features of symbol
1. Unique
Direct useSymbol()
Create a newsymbol
Variable, can choose a string to describe. When the parameter is an object, the of the object is calledtoString()
Methods.
var sym1 = Symbol(); // Symbol()
var sym2 = Symbol('ConardLi'); // Symbol(ConardLi)
var sym3 = Symbol('ConardLi'); // Symbol(ConardLi)
var sym4 = Symbol({name:'ConardLi'}); // Symbol([object Object])
console.log(sym2 === sym3); // false
We use two identical strings to create twoSymbol
Variables, they are not equal, visible eachSymbol
Variables are unique.
If we want to create two equalSymbol
Variables that can be usedSymbol.for(key)
.
Searches for an existing symbol using the given key, and returns the symbol if found. Otherwise, a new symbol will be created in the global symbol registry using the given key.
var sym1 = Symbol.for('ConardLi');
var sym2 = Symbol.for('ConardLi');
console.log(sym1 === sym2); // true
2. Original type
Note the use ofSymbol()
Function creationsymbol
Variables, not constructors, usingnew
The operator will report an error directly.
new Symbol(); // Uncaught TypeError: Symbol is not a constructor
We can usetypeof
Operator to judge aSymbol
Type:
typeof Symbol() === 'symbol'
typeof Symbol('ConardLi') === 'symbol'
3. Enumerable
When usedSymbol
As an object attribute, you can ensure that the object will not have duplicate name attributes, and callfor...in
Can’t enumerate it, otherwise callObject.getOwnPropertyNames、Object.keys()
Nor can it be obtainedSymbol
Property.
Object.getOwnPropertySymbols () can be called to specifically obtain the Symbol property.
var obj = {
name:'ConardLi',
[Symbol('name2')]:'code secret garden'
}
Object.getOwnPropertyNames(obj); // ["name"]
Object.keys(obj); // ["name"]
for (var i in obj) {
console.log(i); // name
}
Object.getOwnPropertySymbols(obj) // [Symbol(name)]
4.2 Symbol Application Scenarios
Here are a fewSymbol
Application scenarios in programs.
Application 1: Preventing XSS
InReact
TheReactElement
Object, there is one$$typeof
Property, which is aSymbol
Variables of type:
var REACT_ELEMENT_TYPE =
(typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) ||
0xeac7;
ReactElement.isValidElement
The React function is used to determine whether a REACT component is valid. The following is its implementation.
ReactElement.isValidElement = function (object) {
return typeof object === 'object' && object ! == null && object.$$typeof === REACT_ELEMENT_TYPE;
};
VisibleReact
When rendering will not$$typeof
Identifiers, as well as components that the rule check fails, are filtered out.
If your server has a vulnerability, allow users to store arbitraryJSON
Object, and client code requires a string, which may become a problem:
// JSON
let expectedTextButGotJSON = {
type: 'div',
props: {
dangerouslySetInnerHTML: {
__html: '/* put your exploit here */'
},
},
};
let message = { text: expectedTextButGotJSON };
<p>
{message.text}
</p>
AndJSON
Cannot store inSymbol
Type, which is to preventXSS
A means of.
Application 2: Private Attributes
With the help ofSymbol
Type cannot be enumerated, we can simulate private properties in the class and control variable reading and writing:
const privateField = Symbol();
class myClass {
constructor(){
this[privateField] = 'ConardLi';
}
getField(){
return this[privateField];
}
setField(val){
this[privateField] = val;
}
}
Application 3: Prevention of Attribute Pollution
In some cases, we may want to add an attribute to the object, which may cause the attribute to be overwrittenSymbol
As an object attribute, it can be guaranteed that an attribute with the same name will never appear.
For example, in the following scenario, we simulate the implementation of acall
Methods:
Function.prototype.myCall = function (context) {
if (typeof this ! == 'function') {
return undefined; //used to prevent Function.prototype.myCall () from calling directly.
}
context = context || window;
const fn = Symbol();
context[fn] = this;
const args = [...arguments].slice(1);
const result = context[fn](...args);
delete context[fn];
return result;
}
We need to call a method temporarily on an object without causing property pollution.Symbol
It is a good choice.
Five, dishonest Number type
Why?Number
Type is not honest, I believe everyone has more or less encountered the problem of inaccurate decimal calculation in the development, such as0.1+0.2! ==0.3
Let’s go back to the source and see why this phenomenon occurs and how to avoid it.
The following is a simple function I implemented to judge whether the addition of two decimals is accurate:
function judgeFloat(n, m) {
const binaryN = n.toString(2);
const binaryM = m.toString(2);
Log (` $ {n} binary is ${binaryN} `);
Log (` $ {m} binary is ${binaryM} `);
const MN = m + n;
const accuracyMN = (m * 100 + n * 100) / 100;
const binaryMN = MN.toString(2);
const accuracyBinaryMN = accuracyMN.toString(2);
Log (` $ {n}+$ {m} binary is ${binaryMN} `);
Log (` $ {accuracymn} binary is $ {accuracybinaryman} `);
Log (` $ {n}+$ {m} binary to decimal is ${to10(binaryMN)} `);
Log (` $ {AccurateMn} binary is converted to decimal again is $ {TO10 (AccurateBinaryMan)} `);
Log (` $ {n}+$ {m} counts as $ {(to10 (binary Mn) = = = to10 (accurate binary ymn)) in js)? '':' not'} exact');
}
function to10(n) {
const pre = (n.split('.')[0] - 0).toString(2);
const arr = n.split('.')[1].split('');
let i = 0;
let result = 0;
while (i < arr.length) {
result += arr[i] * Math.pow(2, -(i + 1));
i++;
}
return result;
}
judgeFloat(0.1, 0.2);
judgeFloat(0.6, 0.7);
5.1 Loss of Precision
All the data in the computer is based onBinary
Stored, so the computer must first convert the data intoBinary
To calculate, and then in the calculation results intoDecimal system
.
It is not difficult to see from the above code, in the calculation0.1+0.2
At that time,Binary
The calculation lost precision, resulting in reconversion intoDecimal system
The results were not in line with the expected results.
5.2 Analysis of Results-More Questions
0.1
And0.2
The binary numbers of the are all decimals with 1100 infinite cycles. Let’s look at the results calculated by JS one by one.
Binary of 0.1:
0.0001100110011001100110011001100110011001100110011001101
Binary of 0.2:
0.001100110011001100110011001100110011001100110011001101
In theory, the sum of the above results should be::
0.0100110011001100110011001100110011001100110011001100111
The binary of 0.1+0.2 calculated by actual JS
0.0100110011001100110011001100110011001100110011001101
See here you may have more problems:
Why is the binary number of 0.1 calculated by js so many bits instead of more bits? ? ?
Why is the binary (0.1+0.2) calculated by js different from the binary (0.1+0.2) calculated by ourselves? ? ?
Why 0.1 binary+0.2 binary! = 0.3 binary? ? ?
5.3 js Storage Method for Binary Decimal Numbers
decimalBinary
Most of them are infinite loops,JavaScript
How do you store them?
InECMAScript® language specificationAs can be seen in,ECMAScript
hit the targetNumber
Type complianceIEEE 754
Standards. It is represented by a 64-bit fixed length.
In fact, many languages follow this standard for numeric types, for exampleJAVA
So many languages have the same problems as above.
So don’t spray when you meet this kind of problem next time.JavaScript
…
If you are interested, you can look at this website.http://0.30000000000000004.com/Yes, you are right, that ishttp://0.30000000000000004.com/! ! !
5.4 IEEE 754
IEEE754
The standard contains a binary representation of a set of real numbers. It consists of three parts:
- Sign bit
- Exponential bit
- Ending digit
The number of bits in each part of floating point numbers with three precision is as follows:
JavaScript
It uses 64-bit double-precision floating-point encoding, so itsSign bit
hold1
Bits, Index Bits11
Bits, mantissa bits accounted for52
Bits.
What do we understand belowSign bit
、Exponential bit
、Ending digit
In order to0.1
For example:
Its binary is:0.0001100110011001100 ...
In order to save storage space, it is expressed by scientific counting in computers, that is
1.100110011001100 ...
X 2-4
If this is not easy to understand, think about decimal numbers:
1100
The scientific counting method of is11
X 102
So:
Sign bit
Is to identify the positive and negative,1
showNegative
,0
showPositive
;
Exponential bit
Store the index of scientific counting method;
Ending digit
Storing the effective number after scientific counting method;
Therefore, the binary we usually see is actually the mantissa bits actually stored by the computer.
ToString(2 in 5.5 js (2)
Since mantissa bits can only be stored52
A number, this can explaintoString(2)
The results of the implementation of the:
If the computer does not have storage space limitations, then0.1
TheBinary
Should be:
0.00011001100110011001100110011001100110011001100110011001 ...
Scientific counting mantissa
1.1001100110011001100110011001100110011001100110011001 ...
However, due to restrictions, the number of significant digits is53
Bits and subsequent numbers cannot be stored, it follows, if so1
Just move forward1
If it is0
The principle of abandoning.
The 53rd bit of the binary scientific counting method of 0.1 is 1, so the following results are obtained:
0.0001100110011001100110011001100110011001100110011001101
0.2
With the same problem, in fact, it is precisely because of such storage that there is a loss of precision, which leads to0.1+0.2! =0.3
.
As a matter of fact, there are still many calculations with the same accuracy problem. We cannot write them all down, so when there are numerical calculations in the program, we’d better use the tool library to help us solve them. Here are two recommended open source libraries:
5.6 The maximum number JavaScript can represent
By andIEEE 754
Limitations of double precision 64-bit specification:
Exponential bit
The maximum number that can be expressed:1023
(Decimal)
Ending digit
The maximum number that can be expressed is the mantissa bit1
The situation of
So the largest number JavaScript can represent is acceded to the throne
1.111 ...
X 21023This result is converted to decimal1.7976931348623157e+308
The result isNumber.MAX_VALUE
.
5.7 Maximum Safety Number
In JavaScriptNumber.MAX_SAFE_INTEGER
Indicates the maximum safety figure. The calculation result is9007199254740991
That is, there will be no loss of precision (except decimals) within this range of numbers, which are actually1.111 ...
X 252.
We can also use some open source libraries to handle large integers:
In fact, the government has also considered this issue.bigInt
Type ines10
It has been proposed in, nowChrome
Can already be used inbigInt
Numbers exceeding the maximum safe number can be operated.
Six, what other reference types
In
ECMAScript
In, a reference type is a data structure used to organize data and functions together.
The object we usually refer to is an instance of a specific reference type.
InECMAScript
In the definition of type, onlyObject
Type, in fact, many of the variables that we usually use to refer to types are not defined byObject
Constructed, but the end points of their prototype chains are allObject
Which are all reference types.
-
Array
array -
Date
Date, -
RegExp
Regular -
Function
Function
6.1 packing type
In order to facilitate the operation of basic type values,ECMAScript
Several special reference types are also provided, which are the basic types of packaging types:
Boolean
Number
String
Note the difference between the package type and the original type:
true === new Boolean(true); // false
123 === new Number(123); // false
'ConardLi' === new String('ConardLi'); // false
console.log(typeof new String('ConardLi')); // object
console.log(typeof 'ConardLi'); // string
The main difference between a reference type and a wrapper type is the lifetime of the object. Instances of the reference type created using the new operator are stored in memory until the execution flow leaves the current scope, while self-primitive types exist only at the moment of execution of a line of code and are then destroyed immediately, which means that we cannot add attributes and methods to the primitive types at runtime.
var name = 'ConardLi'
name.color = 'red';
console.log(name.color); // undefined
6.2 Packing and unpacking
- Boxing conversion: converts the basic type to the corresponding packing type
- Unpacking Operation: Convert Reference Type to Basic Type
Since the original type cannot extend properties and methods, how do we call methods using the original type?
Every time we operate a base type, the background automatically creates an object of wrapper type, allowing us to call some methods and attributes, such as the following code:
var name = "ConardLi";
var name2 = name.substring(2);
In fact, the following processes have taken place:
- Create a
String
The package type instance of - Called on the instance
substring
Method - Destruction instance
In other words, if we call the method using the basic type, we will automatically pack and unpack the case. Similarly, we will use theNumber
AndBoolean
Type, this process also occurs.
The conversion from the reference type to the basic type, that is, the unpacking process, will be followedECMAScript specification
SpecifiedtoPrimitive
Principle, generally will call the reference type ofvalueOf
AndtoString
Method, you can also rewrite it directlytoPeimitive
Methods. Generally, conversion to different types of values follows different principles, such as:
- Reference type converted to
Number
Type, called firstvalueOf
, and then calltoString
- Reference type converted to
String
Type, called firsttoString
, and then callvalueOf
IfvalueOf
AndtoString
Does not exist or does not return a basic typeTypeError
Abnormal.
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
// TypeError
In addition to the automatic unpacking and packing in the program, we can also unpack and pack manually. We can call the wrapper type directlyvalueOf
OrtoString
, realize unpacking operation:
var name =new Number("123");
console.log( typeof name.valueOf() ); //number
console.log( typeof name.toString() ); //string
Seven, type conversion
Because ..JavaScript
Is a weak type of language, so type conversion occurs very frequently, we said above packing and unpacking is actually a type conversion.
Type conversion is divided into two types, implicit conversion is the type conversion that the program automatically performs, and forced conversion is the type conversion that we manually perform.
Forced conversion is no longer mentioned here, let’s take a look at the headache of several scenarios where implicit type conversion may occur, and how to convert:
7.1 Type Conversion Rules
If an implicit conversion occurs, the various types of interconversion conform to the following rules:
7.2 if statement and logical statement
Inif
In statements and logical statements, if there is only a single variable, the variable is first converted toBoolean
Value, only the following cases will be converted tofalse
The rest is converted totrue
:
null
undefined
''
NaN
0
false
7.3 various mathematical operators
We are dealing with all kinds of wrongsNumber
Type uses mathematical operators (- * /
) will not beNumber
Type converted toNumber
Type;
1 - true // 0
1 - null // 1
1 * undefined // NaN
1 - {} // 1
2 * ['5'] // 10
pay attention to+
An exception, execution+
Operator time:
- 1. When one side is
String
Type, which is recognized as string concatenation and will preferentially convert the other side to string type. - 2. When one side is
Number
Type and 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, will reference type andNumber
Type is converted to string and spliced.
123+'123' // 123123 (rule 1)
123+null // 123 (rule 2)
123+true // 124 (rule 2)
123+{} // 123[object Object] (rule 3)
7.4 ==
Use==
When, if both sides are of the same type, the comparison result and===
Same, otherwise implicit conversion will occur, using==
When the conversion can be divided into several different situations (only consider different types on both sides):
- 1.NaN
NaN
Always return compared to any other typefalse
(including himself).
NaN == NaN // false
- 2.Boolean
Boolean
Compare with any other type,Boolean
First converted toNumber
Type.
true == 1 // true
true == '2' // false
true == ['1'] // true
true == ['2'] // false
Note here a point that may be confused:
undefined、null
AndBoolean
Compare, althoughundefined、null
Andfalse
It is easy to imagine false values, but their comparison result isfalse
The reason isfalse
First converted to0
:
undefined == false // false
null == false // false
- 3.String and Number
String
AndNumber
Compare, firstString
Convert toNumber
Type.
123 == '123' // true
'' == 0 // true
- 4.null and undefined
null == undefined
The result of the comparison istrue
In addition to this,null、undefined
The comparison with any other result isfalse
.
null == undefined // true
null == '' // false
null == 0 // false
null == false // false
undefined == '' // false
undefined == 0 // false
undefined == false // false
- 5. Original Type and Reference Type
When comparing the original type with the reference type, the object type followsToPrimitive
Rule converted to original type:
'[object Object]' == {} // true
'1,2,3' == [1, 2, 3] // true
Let’s look at the following comparison:
[] == ! [] // true
!
Has a higher priority than==
,! []
First it will be converted tofalse
According to the third point above,false
Convert toNumber
Type0
, left[]
Convert to0
, both sides are equal.
[null] == false // true
[undefined] == false // true
Based on the array ofToPrimitive
Rules, array elements arenull
Orundefined
, the element is treated as an empty string, so[null]、[undefined]
Will be converted to0
.
Therefore, having said so much, it is recommended to use it.===
To judge whether the two values are equal …
7.5 an interesting interview question
A classic interview question, how to make:a == 1 && a == 2 && a == 3
.
According to the above unpacking conversion, and==
, we can easily write the answer:
const a = {
value:[3,2,1],
valueOf: function() {return this.value.pop(); },
}
Eight, judge JavaScript data types
8.1 typeof
Applicable scenario
typeof
Operators can accurately determine whether a variable is of the following primitive types:
typeof 'ConardLi' // string
typeof 123 // number
typeof true // boolean
typeof Symbol() // symbol
typeof undefined // undefined
You can also use it to judge function types:
typeof function(){} // function
Not applicable scenario
When you usetypeof
To judge the reference type seems a little weak:
typeof [] // object
typeof {} // object
typeof new Date() // object
typeof /^\d*$/; // object
All reference types except functions are determined to beobject
.
In additiontypeof null === 'object'
Also can let a person feel headache, this is inJavaScript
The first edition was handed downbug
After that, many compatibility problems will be caused by the modification and have not been fixed. …
8.2 instanceof
instanceof
Operators can help us determine what type of object the reference type is:
[] instanceof Array // true
new Date() instanceof Date // true
new RegExp() instanceof RegExp // true
Let’s review a few rules of the prototype chain:
- 1. All reference types have object characteristics, that is, they can freely extend attributes.
- 2. All reference types have one
__proto__
The (implicit prototype) attribute is an ordinary object - 3. All functions have
prototype
The (explicit prototype) attribute is also a common object - 4. All Reference Types
__proto__
The whose value points to its constructorprototype
- 5. When trying to get the attribute of an object, if the variable itself does not have this attribute, it will go to him
__proto__
Go find it
[] instanceof Array
In fact, it is judgment.Foo.prototype
Is it in[]
On the prototype chain.
So, useinstanceof
To detect the data type, not very accurate, this is not the original intention of its design:
[] instanceof Object // true
function(){} instanceof Object // true
In addition, useinstanceof
The basic data type cannot be detected either, soinstanceof
It is not a good choice.
8.3 toString
We mentioned above in the unpacking operationtoString
Function, we can call it to convert from a reference type.
Each reference type has
toString
Method, by default,toString()
The method is defined by eachObject
Object inheritance. If this method is not overridden in a custom object,toString()
Return"[object type]"
Of whichtype
Is the type of object.
const obj = {};
obj.toString() // [object Object]
Note that the above mentionedIf this method is not overridden in a custom object
,toString
In fact, most reference types such asArray、Date、RegExp
All of them have been rewrittentoString
Methods.
We can call directlyObject
Not covered on prototypetoString()
Method, usingcall
To changethis
Point to achieve the desired effect.
8.4 jquery
Let’s take a lookjquery
How to judge the type in the source code:
var class2type = {};
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
function( i, name ) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
} );
type: function( obj ) {
if ( obj == null ) {
return obj + "";
}
return typeof obj === "object" || typeof obj === "function" ?
class2type[Object.prototype.toString.call(obj) ] || "object" :
typeof obj;
}
isFunction: function( obj ) {
return jQuery.type(obj) === "function";
}
The original type is used directlytypeof
, the reference type usesObject.prototype.toString.call
Gets the type, using aclass2type
Object filters out excess code from the string, for example[object function]
Will getarray
, and then in the following type judgment, such asisFunction
Can be used directlyjQuery.type(obj) === "function"
This kind of judgment.
References
- http://www.ecma-international …
- https://while.dev/articles/ex …
- https://github.com/mqyqingfen …
- https://juejin.im/post/5bc5c7 …
- https://juejin.im/post/5bbda2 …
- JS Advanced Programming
Summary
I hope you can reach the following points after reading this article:
- Understand
JavaScript
The specific storage form of variables in memory can correspond to the actual scene. - Understand the underlying cause of inaccurate decimal calculation
- Understand the scenarios where implicit type conversion may occur and the conversion principles
- Master judgment
JavaScript
The Way of Data Type and Its Underlying Principle
If there are any mistakes in the article, please correct them in the comment area. If this article helps you, please comment and pay attention.
If you want to read more quality articles, please pay attention to me.github
博客Your star✨, praise and attention are the driving force of my continuous creation!
It is recommended to pay close attention to my WeChat public number “code Secret Garden” and push high-quality articles every day so that we can communicate and grow together.
After paying attention to the public number, reply [Add Group] to pull you into the high-quality front-end communication group.