[JS Advanced] Do you really know the variables and types

Introduction

Variables and types are learningJavaScriptThe 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:

  • JavaScriptWhat is the specific storage form of variables in memory?
  • 0.1+0.2Why not equal to0.3? What are the specific reasons for decimal calculation errors?
  • SymbolWhat are the characteristics and actual application scenarios of?
  • [] == ! [][undefined] == falseWhy 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.JavaScriptKnowledge of variables and types in.

I JavaScript data types

ECMAScript standardSpecified7A data type that combines this7There 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:trueAndfalse
  • Number: integer or floating point number, and some special values (-Infinity+InfinityNaN)
  • String: a string of characters representing text values
  • Symbol: An instance is a unique and unchangeable data type

(ates10The seventh primitive type has been added toBigInt, has now been updatedChromeSupport)

object type

  • ObjectIt is not too much to divide yourself into categories, except for the common ones.Object,ArrayFunctionSuch 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 inECMAScriptIn 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 rightstrSeveral methods were called, without exception. These methods all generated a new string based on the original string instead of directly changing it.strThis proves the immutability of strings.

So, when we continue to call the following code:

str += '6'
 console.log(str);  // ConardLi6

You will find that,strThe value of the has been changed, which makes the character string immutable. In fact, it is not, we understand from memory:

InJavaScriptIn, 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

JavaScriptThe 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 variablestrPoint to this space, so it does not violateImmutableCharacteristics.

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 youJavaScriptHow 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 variablesnameCopy a variablename2At this time, a block of new space is created in memory for storageConardLiAlthough 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.obj2In fact andobjPointed 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 printednameYes'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.ECMAScriptParameters 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:

ECMAScriptParameters of all functions in are passed by value.

Iii. indistinguishable null and undefined

In the original type, there are two typesNullAndUndefined, they all have and have only one value,nullAndundefined, 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 isnullIs normal,nullWhen 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.

undefinedWhen converted to a numerical valueNaN(Special value of non-numeric value)

JavaScriptIs 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 isundefinedWhat’s the point? ForJAVAThis 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

SymbolType isES6An 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 lookSymbolWhat are the characteristics of the type?

4.1 features of symbol

1. Unique

Direct useSymbol()Create a newsymbolVariable, 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 twoSymbolVariables, they are not equal, visible eachSymbolVariables are unique.

If we want to create two equalSymbolVariables 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 creationsymbolVariables, not constructors, usingnewThe operator will report an error directly.

new Symbol();  // Uncaught TypeError: Symbol is not a constructor

We can usetypeofOperator to judge aSymbolType:

typeof Symbol() === 'symbol'
 typeof Symbol('ConardLi') === 'symbol'

3. Enumerable

When usedSymbolAs an object attribute, you can ensure that the object will not have duplicate name attributes, and callfor...inCan’t enumerate it, otherwise callObject.getOwnPropertyNames、Object.keys()Nor can it be obtainedSymbolProperty.

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 fewSymbolApplication scenarios in programs.

Application 1: Preventing XSS

InReactTheReactElementObject, there is one$$typeofProperty, which is aSymbolVariables of type:

var REACT_ELEMENT_TYPE =
(typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) ||
0xeac7;

ReactElement.isValidElementThe 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;
};

VisibleReactWhen rendering will not$$typeofIdentifiers, as well as components that the rule check fails, are filtered out.

If your server has a vulnerability, allow users to store arbitraryJSONObject, 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>

AndJSONCannot store inSymbolType, which is to preventXSSA means of.

Application 2: Private Attributes

With the help ofSymbolType 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 overwrittenSymbolAs 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 acallMethods:

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.SymbolIt is a good choice.

Five, dishonest Number type

Why?NumberType 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.3Let’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);

image

5.1 Loss of Precision

All the data in the computer is based onBinaryStored, so the computer must first convert the data intoBinaryTo calculate, and then in the calculation results intoDecimal system.

It is not difficult to see from the above code, in the calculation0.1+0.2At that time,BinaryThe calculation lost precision, resulting in reconversion intoDecimal systemThe results were not in line with the expected results.

5.2 Analysis of Results-More Questions

0.1And0.2The 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

decimalBinaryMost of them are infinite loops,JavaScriptHow do you store them?

InECMAScript® language specificationAs can be seen in,ECMAScripthit the targetNumberType complianceIEEE 754Standards. It is represented by a 64-bit fixed length.

In fact, many languages follow this standard for numeric types, for exampleJAVASo 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

IEEE754The 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:

image

JavaScriptIt uses 64-bit double-precision floating-point encoding, so itsSign bithold1Bits, Index Bits11Bits, mantissa bits accounted for52Bits.

What do we understand belowSign bitExponential bitEnding digitIn order to0.1For 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:

1100The scientific counting method of is11X 102

So:

image

Sign bitIs to identify the positive and negative,1showNegative,0showPositive;

Exponential bitStore the index of scientific counting method;

Ending digitStoring 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 stored52A number, this can explaintoString(2)The results of the implementation of the:

If the computer does not have storage space limitations, then0.1TheBinaryShould be:

0.00011001100110011001100110011001100110011001100110011001  ...

Scientific counting mantissa

1.1001100110011001100110011001100110011001100110011001  ...

However, due to restrictions, the number of significant digits is53Bits and subsequent numbers cannot be stored, it follows, if so1Just move forward1If it is0The 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.2With 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 754Limitations of double precision 64-bit specification:

Exponential bitThe maximum number that can be expressed:1023(Decimal)

Ending digitThe maximum number that can be expressed is the mantissa bit1The situation of

So the largest number JavaScript can represent is acceded to the throne

1.111 ...X 21023This result is converted to decimal1.7976931348623157e+308The result isNumber.MAX_VALUE.

5.7 Maximum Safety Number

In JavaScriptNumber.MAX_SAFE_INTEGERIndicates the maximum safety figure. The calculation result is9007199254740991That 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.bigIntType ines10It has been proposed in, nowChromeCan already be used inbigIntNumbers exceeding the maximum safe number can be operated.

Six, what other reference types

InECMAScriptIn, 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.

InECMAScriptIn the definition of type, onlyObjectType, in fact, many of the variables that we usually use to refer to types are not defined byObjectConstructed, but the end points of their prototype chains are allObjectWhich are all reference types.

  • Arrayarray
  • DateDate,
  • RegExpRegular
  • FunctionFunction

6.1 packing type

In order to facilitate the operation of basic type values,ECMAScriptSeveral 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 aStringThe package type instance of
  • Called on the instancesubstringMethod
  • 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 theNumberAndBooleanType, this process also occurs.

The conversion from the reference type to the basic type, that is, the unpacking process, will be followedECMAScript specificationSpecifiedtoPrimitivePrinciple, generally will call the reference type ofvalueOfAndtoStringMethod, you can also rewrite it directlytoPeimitiveMethods. Generally, conversion to different types of values follows different principles, such as:

  • Reference type converted toNumberType, called firstvalueOf, and then calltoString
  • Reference type converted toStringType, called firsttoString, and then callvalueOf

IfvalueOfAndtoStringDoes not exist or does not return a basic typeTypeErrorAbnormal.

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 directlyvalueOfOrtoString, realize unpacking operation:

var name =new Number("123");
console.log( typeof name.valueOf() );  //number
console.log( typeof name.toString() );  //string

Seven, type conversion

Because ..JavaScriptIs 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

InifIn statements and logical statements, if there is only a single variable, the variable is first converted toBooleanValue, only the following cases will be converted tofalseThe rest is converted totrue

null
undefined
''
NaN
0
false

7.3 various mathematical operators

We are dealing with all kinds of wrongsNumberType uses mathematical operators (- * /) will not beNumberType converted toNumberType;

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 isStringType, which is recognized as string concatenation and will preferentially convert the other side to string type.
  • 2. When one side isNumberType and the other side is the original type, the original type is converted toNumberType.
  • 3. When one side isNumberType, on the other side is the reference type, will reference type andNumberType 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

NaNAlways return compared to any other typefalse(including himself).

NaN == NaN // false
  • 2.Boolean

BooleanCompare with any other type,BooleanFirst converted toNumberType.

true == 1  // true
true == '2'  // false
true == ['1']  // true
true == ['2']  // false

Note here a point that may be confused:undefined、nullAndBooleanCompare, althoughundefined、nullAndfalseIt is easy to imagine false values, but their comparison result isfalseThe reason isfalseFirst converted to0

undefined == false // false
 null == false // false
  • 3.String and Number

StringAndNumberCompare, firstStringConvert toNumberType.

123 == '123' // true
'' == 0 // true
  • 4.null and undefined

null == undefinedThe result of the comparison istrueIn addition to this,null、undefinedThe 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 followsToPrimitiveRule 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 tofalseAccording to the third point above,falseConvert toNumberType0, left[]Convert to0, both sides are equal.

[null] == false // true
 [undefined] == false // true

Based on the array ofToPrimitiveRules, array elements arenullOrundefined, 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

typeofOperators 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 usetypeofTo 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 inJavaScriptThe first edition was handed downbugAfter that, many compatibility problems will be caused by the modification and have not been fixed. …

8.2 instanceof

instanceofOperators 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 haveprototypeThe (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 ArrayIn fact, it is judgment.Foo.prototypeIs it in[]On the prototype chain.

So, useinstanceofTo 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, useinstanceofThe basic data type cannot be detected either, soinstanceofIt is not a good choice.

8.3 toString

We mentioned above in the unpacking operationtoStringFunction, we can call it to convert from a reference type.

Each reference type hastoStringMethod, by default,toString()The method is defined by eachObjectObject inheritance. If this method is not overridden in a custom object,toString()Return"[object type]"Of whichtypeIs the type of object.

const obj = {};
 obj.toString() // [object Object]

Note that the above mentionedIf this method is not overridden in a custom object,toStringIn fact, most reference types such asArray、Date、RegExpAll of them have been rewrittentoStringMethods.

We can call directlyObjectNot covered on prototypetoString()Method, usingcallTo changethisPoint to achieve the desired effect.

8.4 jquery

Let’s take a lookjqueryHow 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.callGets the type, using aclass2typeObject filters out excess code from the string, for example[object function]Will getarray, and then in the following type judgment, such asisFunctionCan be used directlyjQuery.type(obj) === "function"This kind of judgment.

References

Summary

I hope you can reach the following points after reading this article:

  • UnderstandJavaScriptThe 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 judgmentJavaScriptThe 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.