Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

The JS data type that the junior front end must know


May 31, 2021 Article blog


Table of contents


What data types are available in JavaScript?

The types of data defined in the computer world are actually defined to describe the facts that exist in the real world. For example, we use people as examples:

  1. Is there anyone in the room? There is and there is no concept of right or wrong, corresponding to Boolean type in JS true for yes, false for non;
  2. How many people are in the room? Here are a few representations of a magnitude concept, corresponding to Number type in JS containing integers and floats, and some special values, such as: -Infinity for negative infinity, +Infinity for positive infinity, NaN for not a number;
  3. These people in the room are all my friends. This is a statement statement, and the information for this text class is stored as a string, corresponding to the String type in JS
  4. There is no one in the room. There is no concept of nothing and empty here, which can be expressed in both null and undefined in JS
  5. Everyone in the real world is unique, and this corresponds to the Symbol type in JS indicating that it is unique and immutable;
  6. Number integer represented by Number is a range, and out-of-range data cannot be represented by Number so a new data BigInt is proposed in ES10 that can represent the integer of any number of digits;
  7. The seven types mentioned above, Boolean Number String null undefined Symbol and BigInt are the original types in JavaScript and one is a non-original type called an object type;

let person = {
    name: 'bubuzou',
    sex: 'male',
    age: 26,}

Why distinguish between the original type and the object type? What's the difference between them?

The immutability of the original type

Before we answer this question, let's look at how variables are stored in memory:

let name1 = 'bubuzou'
let name2 = name1.concat('.com')
console.log(name1)  // 'bubuzou'

After executing the above code, we find that the value of the variable name1 remains the same and bubuzou T his illustrates the immutability of strings. But if you look at the following code, you'll have questions:

let name1 = 'bubuzou'
name1 += '.com'
console.log(name1)  // 'bubuzou.com'

You said the string was immutable, wasn't it? I n fact, this is only the value of the variable has changed, but the strings that exist in memory remain unchanged. T his involves the storage of variables in memory. I n JavaScript variables are stored in memory in two ways: in the stack and in the heap. So what's the difference between stack memory and heap memory?

Stack memory:

  • Sequential storage structure, characterized by advanced back out. Like a soldier ping-pong ball box, the soldier ping-pong ball from the outside into the box, the first to take out must be the last to put into the box.
  • The storage space is fixed
  • You can manipulate its saved values directly and perform them efficiently

Heap memory:

  • A disordered storage structure
  • Storage space can change dynamically
  • Its internal storage cannot be operated directly and needs to be done by reference address

After understanding that there are two ways variables can be stored in memory, let's continue to draw a diagram of the storage structure of the variables using the above string of code as an example:

 The JS data type that the junior front end must know1

Then we can describe what happened when the computer executed this code. F irst a variable name1 is defined and assigned a bubuzou which opens up a space in memory to store the string bubuzou and then the variable points to that memory space. T hen execute the second line of code letname2=name1.concat('.com') the stitching operation here actually produces a new string bubuzou.com so a new piece of memory is created for the new string and the defined variable name2 is pointed to this memory address. So we see that the whole operation bubuzou this string is in the memory is actually unchanged, even in the second piece of code to perform name1+='.com' operation, in fact, it is only the variable name1 points to the new string bubuzou.com the old string bubuzou still exists in memory, but after a while because the string is not referenced by the variable, so it will be garbage collection, thus freeing up the block of memory space.

Thus we conclude that the values of the original type are fixed, while the object types are combined into a complex object by the key value pairs of the original type;

Think of a question why the value of the reference type is stored in heap memory? C an it be stored in stack memory? Answer 1: Because the reference type size is not fixed, and the size of the stack is fixed, the size of the heap space can be dynamically changed, so the value of the reference type is suitable for the existence of the heap;

compare

When we compare two variables, different types of variables behave differently:

let str1 = 'hello'
let str2 = 'hello'
console.log( str1 === str2 ) // true
let person1 = {
    name: 'bubuzou'
}
let person2 = {
    name: 'bubuzou'
}
console.log( person1 === person2 )  // false

We have defined two string variables and two object variables, all of which are identical in length, but the string variables are equal and the object variables are not. T his is because in JavaScript prototype types are compared to whether the values in the stack are equal, and reference types are compared to whether reference addresses in stack memory are equal. The storage model for the previous variables in memory is shown in the figure:

 The JS data type that the junior front end must know2

copy

When a variable is copied, there is a difference between the original type and the reference type variable, so let's look at the following code:

let str1 = 'hello'
let str2 = str1
str2 = 'world'
console.log( str1 ) // 'hello'

 The JS data type that the junior front end must know3

  1. letstr1='hello' Before copying, a variable str1 is defined and assigned hello at which point the hello string is allocated a piece of space in the stack memory for storage, and then the variable str1 points to this memory address;
  2. letstr2=str1 After copying, assign the value of str1 to str2 at which point a new space is opened in the stack to store the value of str2
  3. str2='world' assign str2 a new string world then a new piece of memory will be used to store world while the memory space of str2 original value hello will be garbage collected after a period of time because there are no variable references;
  4. console.log(str1) Because str1 and str2 have different stack memory addresses, even if the value of str2 is changed, str1 is not affected.

Then let's move on and look at the replication of the reference type:

let person1 = {
    name: 'bubuzou',
    age: 20
}
let person2 = person1
person2.name = 'bubuzou.com'
console.log( person1.name)  // 'bubuzou.com'

 The JS data type that the junior front end must know4

When the original type is copied, the value of the variable is re-assigned, as shown in the figure above: when the reference type is copied, the reference address to which the variable points is assigned to the new variable, so after person1 and person2 point to the same value in heap memory, so when person2.name is changed, person1.name is also changed for this reason.

Value delivery and reference delivery

Let's start with the conclusion that in JavaScript the arguments of all functions are passed by value. Here's the code:

let name = 'bubuzou'
function changeName(name) {
    name = 'bubuzou.com'
}
changeName(name)
console.log( name )  // 'bubuzou'

A variable name is defined and assigned bubuzou which is name in when the function is called, at which point a local variable name is created inside the function and the value of the global variable bubuzou passed to him, which is actually a new piece of memory to hold the value of the local variable, and then The value of the local variable is changed to bubuzou.com this time there will be 3 pieces of address space in memory to hold the value of the global variable bubuzou the original value of the local variable bubuzou and the new value of the local variable bubuzou.com After a while, because the old and new values name the local variables do not have variable bubuzou the two spaces will be reclaimed and released;

If you look at the reference type of argument, will it be different?

let person = {
    name: 'bubuzou'
}
function changePerosn(person) {
    person.name = 'bubuzou.com'
}
changePerosn( person )
console.log( person.name )  // 'bubuzou.com'

When the reference type is a function argument, the reference address is copied to the local variable, so the global person and the local variable person function person point to the same heap address, so once one side changes, the other party will also be changed, so at this point we can conclude that: when the function is ginseng, if the argument is a reference type then is a reference pass?

Under the example above:

let person = {
    name: 'bubuzou'
}
function changePerosn(person) {
    person.name = 'bubuzou.com'
    person = {        name: 'hello world'    
    }
}
changePerosn( person )
console.log( person.name )  // 'bubuzou.com'

If person is passed by reference, it automatically points person to a new object whose value has person been changed to hello world

null and undefined silly can't tell?

null is a primitive type in JavaScript with only one value null representing special values such as none, empty, unknown values, and so on. You can assign a variable a null directly:

let s = null

undefined like null is a self-contained primitive type, meaning that a variable is defined but not assigned, the value of the variable is undefined :

let s
console.log( s)  // undefined

Although it is not wrong to assign a variable a direct value of undefined in principle it is appropriate to assign a direct assignment to null if a variable value is undeterred or indicates empty, and it is not recommended to assign a variable a value undefined null and undefined return false when making logical judgments:

let a = null, b
console.log( a ? 'a' : b ? 'b' : 'c') // 'c'

null becomes 0 when it is converted to a number type, and undefined becomes NaN :

let a = null, b
console.log( +null )  // 0
console.log( + b )  // NaN

Recognize the new original type Symbol

Symbol value represents a unique identifier and is a newly introduced primitive type in ES6 You can create an important value through Symbol() or pass in a description value whose uniqueness is that even incoming descriptions do not equal between them:

let a = Symbol('bubuzou')
let b = Symbol('bubuzou')
console.log( a === b )  // false

Global Symbol

So isn't any two Symbol described the same unequi equal? T he answer is no. You can find or create a new Symbol by Symbol.for()

let a = Symbol.for('bubuzou')
let b = Symbol.for('bubuzou')
console.log( a === b )  // true

Symbol.for() allows you to look globally based on the incoming description, create a new Symbol if it is not found, and return it, so when you execute the second line of code Symbol.for('bubuzou') you will find the Symbol described globally as bubuzou so here a and b will be absolutely equal.

If you can find Symbol by description, can you find it through Symbol The answer is yes, but it must be a global Symbol and if not found, undefined is returned :

let a = Symbol.for('bubuzou')
let desc = Symbol.keyFor( a )
console.log( desc )  // 'bubuzou'

However, for any Symbol there is a property description that description the description of the Symbol

let a = Symbol('bubuzou')
console.log( a.description )  // 'bubuzou'

Symbol is an object property

We know that an object's property key can be a string, but not Number or Boolean Symbol was designed to be the property key for the object:

let age = Symbol('20')
let person = {
    name: 'bubuzou', 
    [age]: '20',  // 在对象字面量中使用 `Symbol` 的时候需要使用中括号包起来
}

A Symbol is person here as a property key, which is better than using a string as a property key? The most obvious benefit is that if this person object is developed and maintained by multiple developers, it is easy to add properties to person with the same name, and if you use strings as property keys, that's definitely a conflict, but if you use Symbol as a property key, there's no problem because it's a unique identifier, so you can protect the properties of the object from accidental access or overrides.

Note that if you use Symbol as the property key for an object, the loop here forin Object.getOwnPropertyNames or Object.keys() cannot get Symbol property key, but it can be obtained through Object.getOwnPropertySymbols()

for (let o in person) {
    console.log( o ) // 'name'
}
console.log (Object.keys( person )) // ['name']
console.log(Object.getOwnPropertyNames( person ))  // ['name']
console.log(Object.getOwnPropertySymbols( person ))  // [Symbol(20)]

Number type that you may not know

There are two types of numbers involved in JavaScript the Number type, stored in 64 IEEE-754 as double floats, which is the number we normally use, which ranges from $2 to {52} The second type is BigInt which represents integers of any length, from $2 to {52} -${52}$ to -$2.{52}$. Here we only cover Number numbers.

Regular and special numbers

For a regular number, we can write it directly, for example:

let age = 20

But there is also a particularly large number of numbers that we are used to using the representation of scientific counting:

let billion = 1000000000;
let b = 1e9

The above two formulations mean that 1e9 means 1 x $10,9$, and if it is 1e-3 1 / $10,3$, 0.001. In JavaScript you can also represent different indents with numbers, such as 10 in decimals that can be represented as 0b1010 0o12 and 0xa in binary, 0b and 0xa respectively, where 0b is a binary prefix, 0o is an octal prefix, and ox is a hex prefix.

We can also convert between feeds using the toString(base) base method, which is the cardinality of the feed, representing the decimal, which defaults to 10 system and returns a string representation of the converted value. Like what:

let num = 10
console.log( num.toString( 2 ))  // '1010'
console.log( num.toString( 8 ))  // '12'
console.log( num.toString( 16 ))  // 'a'

Numbers can also be called directly by method, 10..toString(2) Here's 2 . number is not wrong, but must be 2, otherwise SyntaxError error will be reported. T he first point represents the decimal point, and the second is the calling method. P oint symbols are first considered part of the numeric constant, and secondly as property accesses, and if only one point is written, the computer cannot know whether this represents a decimal or a function. There are several ways to write a numeric direct call function:

(10).toString(2)  // 将10用括号包起来
10.0.toString(2)  // 将10写成10.0的形式
10 .toString(2)   // 空格加上点符号调用

In addition to regular numbers, the Number type contains some special numbers:

  • NaN Represents not a number, usually the result of unreasonable calculations, such as numbers divided by string 1/'a' NaN and any number of comparisons are false including himself: NaN==NaN returns false H ow can I tell if a number is NaN There are four ways:

Method 1: With isNaN() function, this method also returns true to the incoming string, so the judgment is inaccurate and is not recommended:

isNaN( 1 / 'a')`  // true
isNaN( 'a' )  // true

Method 2: By Number.isNaN() it is recommended to use:

Number.isNaN( 1 / 'a')`  // true
Number.isNaN( 'a' )  // false

Method 3: By Object.is(a,isNaN) :

Object.is( 0/'a', NaN) // true
Object.is( 'a', NaN) // false

Method 4: N n NaN by judging n!==n and returning true :

let s = 1/'a'
console.log( s !== s )  // true

  • +Infinity represents positive infinity, such as the result of 1/0 calculation, -Infinity negative infinity, such as the result of -1/0
  • +0 -0 in JavaScript are positive and negative, including zero, and they are absolutely equal:

console.log( +0 === -0 )  // true

Why is 0.1 plus 0.2 not equal to 0.3?

console.log( 0.1 + 0.2 == 0.3 )  // false

Have you ever wondered why the above is not equal? Because numbers are stored in binary within JavaScript they follow IEEE754 standard, store a number in 64 bits, and 64 bits are separated into 1 11 and 52 bits to represent the sign, exponential, and tail digits, respectively.

 The JS data type that the junior front end must know5

For example, what is the decimal 0.1 after conversion to binary? We manually calculate that the decimal decimal to binary decimal rule is "multiplier 2 rounding, sequential arrangement", the specific approach is: with 2 times decimal decimals, you can get the product, the integer part of the product is removed, and then use 2 times the remaining decimal part, and then get a product, and then the whole part of the product is taken out, so that until the decimal part of the product is zero, or to achieve the required accuracy.

0.1 * 2 = 0.2  // 第1步:整数为0,小数0.2
0.2 * 2 = 0.4  // 第2步:整数为0,小数0.4
0.4 * 2 = 0.8  // 第3步:整数为0,小数0.8
0.8 * 2 = 1.6  // 第4步:整数为1,小数0.6
0.6 * 2 = 1.2  // 第5步:整数为1,小数0.2
0.2 * 2 = 0.4  // 第6步:整数为0,小数0.4
0.4 * 2 = 0.8  // 第7步:整数为0,小数0.8...

After we calculate this in turn, we find that the order of the integers is 0001100110011001100.... Infinite loop, so theoretically 0.1 will be an infinite decimal 0.0001100110011001100... , represented by scientific counting, will be 1.100110011001100... x $2,400, but since IEEE754 standard specifies that a number can only be 64 digits and a significant number in 52 digits, a total of 52 bits will be rounded to 1100110011001100.... This infinite number is rounded to a total of 52 digits as valid bits, T hen the binary end trade-off rule is to look at the last digit if 1 is in place, and if it is 0 then directly rounded. S o since the 53 digit of this string of numbers is exactly 1 the final number is 1100110011001100110011001100110011001100110011001101 1.100110011001100110011001100110011001100110011001101 x $2.-4. 1100110011001100.... Decimal-to-binary can also be toString

console.log( 0.1.toString(2) )  // '0.0001100110011001100110011001100110011001100110011001101'

We found that 0.1 loses precision when converted into binary decimals, which is larger than the real value due to entry. 0.2 actually has this problem and there is a loss of precision, so in fact 0.1+0.2 will not be equal to 0.3 :

console.log( 0.1 + 0.2 )  // 0.30000000000000004

Is it impossible to tell if the two decimal places are equal? The answer must be no, and trying to determine whether the two decimals n1 and n2 are equal can be done as follows:

  • Method 1: If the absolute value of the difference between two decimals is smaller than Number.EPSILON then the two numbers are equal.

Number.EPSILON is the error accuracy in ES6 and the actual value can be considered equal to $2.

if ( Math.abs( n1 - n2 ) < Number.EPSILON ) {
    console.log( 'n1 和 n2 相等' )
}

  • Method 2: Round the results by toFixed(n) toFixed() will return the string, and we can turn it into a number with a dollar plus +

let sum = 0.1 + 0.2
console.log( +sum.toFixed(2) === 0.3 )  // true

Conversion of values

When working with numbers, you often encounter the rounding of values and string-to-number problems, and here we consolidate the foundation. Let's start with rounding:

  • Math.floor() round down to get an integer:

Math.floor(2.2)  // 2
Math.floor(2.8)  // 2

  • Math.ceil() rounded up to get an integer:

Math.ceil(2.2)  // 3
Math.ceil(2.8)  // 3

  • Math.round() rounds the first decimal place:

Math.round(2.26)  // 2
Math.round(2.46)  // 2
Math.round(2.50)  // 3

  • Number.prototype.toFixed(n) like Math.round() rounds the number to n bits after the decimal point and returns as a string:

12..toFixed(2)  // '12.00'
12.14.toFixed(1)  // '12.1'
12.15.toFixed(1)  // '12.2'

Why is 6.35.toFixed(1) equal to 6.3 Because 6.35 is actually an infinite decimal:

6.35.toFixed(20)  // "6.34999999999999964473"

So at 6.35.toFixed(1) you get 6.3

Let's take a look at string-to-number situations:

  • Number(n) or +n directly n for strict conversion:

Number(' ')  // 0
console.log( +'') // 0
Number('010')  // 10
console.log( +'010' )  // 10
Number('12a')  // NaN
console.log( +'12a' )  // NaN

  • parseInt() a non-strict conversion, parses strings from left to right, stops parsing when confronted with non-numbers, and returns parsed numbers:

parseInt('12a')  // 12
parseInt('a12')  // NaN
parseInt('')  // NaN
parseInt('0xA')  // 10,0x开头的将会被当成十六进制数

parseInt() is used by default to parse strings in decimals, but in fact he supports the second argument passed in, indicating how many cardinality to parse the first argument:

parseInt('1010', 2)  // 10
parseInt('ff', 16)  // 255

How can I tell if a number is an integer? Describes two approaches:

  • Method 1: Through Number.isInteger() :

Number.isInteger(12.0)  // true
Number.isInteger(12.2)  // false

  • Method two: typeofnum=='number'&&num%1==0

function isInteger(num) {
    return typeof num == 'number' && num % 1 == 0
}

The reference type

In addition to the original type, there is a particularly important type: the reference type. T he elevation describes him as a reference type, a data structure that organizes data and functionality together. By far the most reference type we've seen is Object and there are two ways to create an Object

  • Mode 1: Through the new operator:

let person = new Object()
person.name = 'bubuzou'
person.age = 20

  • Mode 2: Through the literal volume of the object, this is our favorite way to use:

let person = {
    name: 'bubuzou',
    age: 20
}

Built-in reference type

In addition to Object there are other built-in reference types in JavaScript such as:

  • Array array
  • Date date
  • RegExp regular expression
  • Function function

The top of their prototype chain points to Object :

let d = new Date()
console.log( d.__proto__.__proto__.constructor )  // ƒ Object() { [native code] }

The type of packaging

Let's start with the question, why do variables of the original type have no properties and methods, but are able to call methods?

let str = 'bubuzou'
str.substring(0, 3)  // 'bub'

Because JavaScript has designed several corresponding packaging types to better manipulate the original type, they are:

  • Boolean
  • Number
  • String

The execution of the above string of code is actually like this:

  1. Create an instance of the String type;
  2. Call the specified method on the instance;
  3. Destroy this instance

In code:

let str = new
String('bubuzou')
str.substring(0, 3)
str = null

The original type call function is actually an automatic boxing operation, the original type into a wrapper type, and then in fact the original type and the packaging type are fundamentally different, the original type is the original value, and the wrapper type is an instance of the object:

let str1 = 'bubuzou'
let str2 = new String('bubuzou')
console.log( str1 === str2 )  // fasle
console.log( typeof str1 )  // 'string'
console.log( typeof str2 )  // 'object'

There is actually a boxing operation, that must also have unboxing operations, the so-called unboxing is the packaging type into the original type of process, also known as ToPromitive to see the following example:

let obj = {
    toString: () => { return 'bubuzou' },    
    valueOf: () => { return 20 },
}
console.log( +obj )  // 20
console.log( `${obj}` )  // 'bubuzou'

When unboxing, the toString() and valueOf() methods of the wrapper type are tried by default, and the order of hint calls varies, and if hint is string toString() is called first, otherwise valueOf() is called first. By default, an Object object has toString() and valueOf() methods:

let obj = {}
console.log( obj.toString() )  // '[object Object]'
console.log( obj.valueOf() )  // {},valueOf会返回对象本身

Type change

Javascript is a weak type of speech, so type conversions often occur when working on variables, especially implicit type conversions, which can make code execution unexpected, such as the following code, can you understand the results of its execution?

[] + {}  // '[object Object]'
{} + []  // 0

Type conversion rules

So we need to know the rules for type conversion, and here's a table that lists common values and types and post-conversion results for informational purposes only.

 The JS data type that the junior front end must know6

The type conversion is displayed

We usually write code should try to make the written code easy to understand, so that others can read after you know what you are going to do, so when judging the type should try to show the processing. For example, if you turn a string into a number, you can do this:

Number( '21' )  // 21
Number( '21.8' )  // 21.8
+'21'  // 21 

Turning a number display into a string can do this:

String(21)  // '21'
21..toString()  // '21'

The display can be converted to a Boolean type as this:

Boolean('21')  // true
Boolean( undefined )  // false
!!NaN  // false
!!'21'  // true

In addition to the above, there are some cold operations on type conversion that sometimes work: get the number of milliseconds of the current time directly with a dollar plus operator:

+new Date()  // 1595517982686

Transfer the results of the operation directly to the Boolean type with the ~ indexOf()

let str = 'bubuzou.com'
if (~str.indexOf('.com')) {
    console.log( 'str如果包含了.com字符串,则会打印这句话' )
}

~~ an integer with a character or number is slightly different from Math.floor()

~~21.1  // 21
~~-21.9  // -21
~~'1.2a'  // 0
Math.floor( 21.1 )  // 21
Math.floor( -21.9 )  // -22

Implicit type conversion

Implicit type conversion occurs at the runtime of JavaScript usually caused by some operator or statement, in the following cases:

  • Implicitly converted to Boolean type:

  1. if(..) The condition in the statement determines the expression.
  2. for(..;..;..) The condition in the statement determines the expression (second).
  3. while(..) a nd do..while(..) The condition in the loop determines the expression.
  4. ?: The condition in the judgment expression.
  5. The number of operations to the left of the logical || && or) and (logic and) (as a conditional expression)

if (42) {
    console.log(42)
}
while ('bubuzou') {
    console.log('bubuzou')
}
const c = null ? '存在' : '不存在'  // '不存在'

The non-Boolean values in the example above are implicitly cast to Boolean values for conditional judgment. S pecial attention should be paid to || and . && operators. || The procedure is to evaluate the left side only when the value on the left returns false and return it as the final result, with effects such as a?a:b

const a = 'a' || 'b'  // 'a'
const b = '' || 'c'  // 'c'

The procedure for && is to evaluate the right side only when the value on the left returns true and return the value on the right as a result, similar to the effect a?b:a

const a = 'a' && 'b'  // 'b'
const b = '' && 'c'  // ''

  • The mathematical operator -*/ takes precedence over non-numeric types to number types, but is special for +

  1. When one side is a String type, it is recognized as a string stitching, and the other side is converted to a string type first.
  2. When one side is the Number type and the other side is the original type, the original type is converted to Number type.
  3. When one side is a Number type and the other side is a reference type, the reference type and Number type are stitched after converting the reference type to a string.

42 + 'bubuzou'  // '42bubuzou'
42 + null  // 42
42 + true  // 43
42 + []  // '42'
42 + {}  // '42[object Object]'

  • Loose equality and strict equidity

Relaxed equivalement == and strict equivaleity === often asked during interviews, and the answer is generally == to determine whether the values are equal, and to determine whether the types are equal in addition to whether the values will be equal, the answer is not entirely correct, and the better answer is: . === == === So == type conversion work?

1, the number and string ratio, the string will be converted to a number for comparison:

20 == '20'  // true
20 === '20'  // false

2, other types and Boolean type comparison, Boolean type will first be converted to a number to compare, true to the number 1 false to the number 0 note that this is a very error-prone point:

'bubuzou' == true  // false
'0' == false  // true
null == false  // false,
undefined == false  // false
[] == true  // false
['1']  == true  // true

So when writing code for judgment, be sure not to write it as x==true or x==false but as a direct if(x) judgment.

3, null and undefined : the result of null==undefined comparison is true except that the comparison values for null undefined and any other results are false It can be assumed that null and undefined can be implicitly typed to each other in the case of ==

null == undefined // true
null == '' // false
null == 0 // false
null == false // false
undefined == '' // false
undefined == 0 // false
undefined == false // false

4, the original type and reference type comparison, the reference type will first ToPromitive converted to the original type and then compared, the rule refers to the unboxing operation described above:

'42'  == [42]  // true
'1,2,3'  == [1, 2, 3]  // true
'[object Object]' == {}  // true
0 == [undefined]  // true

5, special value

NaN == NaN  // false
+0 == -0  // true
[] == ![]  // true,![]的优先级比==高,所以![]先转成布尔值变成false;即变成[] == falsefalse再转成数字0,[]转成数字0,所以[] == ![]
0 == '\n'  // true

Type detection

The original type is detected with typeof

JavaScript has six original types, null undefined boolean number string Symbol and so on, and we can use typeof to determine what the value is, returning a string representation of the type:

typeof undefined // 'undefined'
typeof true  // 'boolean'
typeof 42  // 'number'
typeof "42"  // 'string'
typeof Symbol()  // 'symbol'

But there is one exception to the original type, typeofnull gets 'object', so we can't get an accurate answer when we type the original value with typeof so how do we tell if a value is null type?

let o = null
!o && typeof o === 'object' // 用于判断 o 是否是 null 类型

What's the difference undeclared undefined The former is a variable that is defined in scope but not undeclared while the latter is a variable that is not undefined in scope;

typeof can judge the original type, so can it also judge the reference type?

typeof []  // 'object'
typeof {}  // 'object'
typeof new Date()  // 'object'
typeof new RegExp()  // 'object'
typeof new Function()  // 'function'

From the above results we can draw the conclusion that typeof can function be correctly judged when judging a reference type, and nothing else can correctly judge exactly what reference type is.

Use instanceof to detect reference types

We know that typeof can only detect some of the original types, and there is nothing we can do about reference types. JavaScript provides an operator instanceof so let's see if he can detect the reference type:

[] instanceof Array  // true
[] instanceof Object  // true 

We found that the array is an instance of Array and an instance of Object because the end point of the reference type prototype chain is Object so Array is naturally an instance of Object So let's conclude: instanceof use to detect reference types doesn't seem like a very reliable choice either.

Type detection with toString

We can use Object.prototype.toString.call() to detect the type of any variable value:

Object.prototype.toString.call(true)  // '[object Boolean]'
Object.prototype.toString.call(undefined)  // '[object Undefined]'
Object.prototype.toString.call(null)  // '[object Null]'
Object.prototype.toString.call(20)  // '[object Number]'
Object.prototype.toString.call('bubuzou')  // '[object String]'
Object.prototype.toString.call(Symbol())  // '[object Symbol]'
Object.prototype.toString.call([])  // '[object Array]'
Object.prototype.toString.call({})  // '[object Object]'
Object.prototype.toString.call(function(){})  // '[object Function]'
Object.prototype.toString.call(new Date())  // '[object Date]'
Object.prototype.toString.call(new RegExp())  // '[object RegExp]'
Object.prototype.toString.call(JSON)  // '[object JSON]'
Object.prototype.toString.call(MATH)  // '[object MATH]'
Object.prototype.toString.call(window)  // '[object RegExp]'

The article comes from the public number: The sea I'm coming, author Bran

The above is W3Cschool编程狮 about the junior high school front end must know the JS data type of the relevant introduction, I hope to help you.