as an entry-level knowledge point of JavaScript, JS data type is actually particularly important in the whole learning process of JavaScript. Because in JavaScript programming, we often encounter the problem of judging boundary data type conditions. Many codes can be reliably executed only under a specific data type.
this lecture combs and deeply studies the knowledge points of JavaScript data types from the aspects of data type concept, detection method and conversion method.
I hope that through the study of this lecture, I can skillfully master the relevant knowledge points such as data type judgment and conversion, and can easily deal with problems such as data type judgment and implicit conversion.
Data type concept
there are 8 data types of JavaScript:
undefined,Null,Boolean,String,Number,Symbol,BigInt,Object: Array,RegExp,Date,Math,Function
the first seven types are the basic types, and the last one (Object) is the reference type, which also needs to be paid attention to, because it is the data type most frequently used in daily work and needs to pay attention to the most technical details.
reference data types (objects) are divided into these common types on the graph: Array - Array Object, RegExp regular Object, date - Date Object, Math - mathematical Function, Function - Function Object.
here, we will focus on the following two points. Because various JavaScript data types will be placed in different memory after initialization, the above data types can be roughly divided into two categories for storage:
- The basic type is stored in the stack memory. When it is referenced or copied, an exactly equal variable will be created;
- The reference type is stored in the heap memory. It stores addresses. Multiple references point to the same address. Here, a concept of "sharing" will be involved.
as for reference types, we will explain them directly through two pieces of code to deeply understand the core concept of "sharing".
Topic 1: fledgling
let a = { name: 'lee', age: 18 } let b = a; console.log(a.name); //First console b.name = 'son'; console.log(a.name); //Second console console.log(b.name); //The third console
this question is relatively simple. You can see that the name of the first console is' lee ', which should be no doubt; However, after b.name='son 'is executed, it is found that the attribute name of a and B is' son', and the second and third print results are the same. Here, the "sharing" feature of reference type is reflected, that is, the two values are shared in the same memory. One changes and the other changes accordingly.
Topic 2: getting better
let a = { name: 'Julia', age: 20 } function change(o) { o.age = 24; o = { name: 'Kath', age: 30 } return o; } let b = change(a); //Note that there is no new here. There will be a special article on new later console.log(b.age); // First console console.log(a.age); // Second console
this question involves function. Through the above code, you can see that the result of the first console is 30, b and the final print result is {name: "Kath", age: 30}; The return result of the second console is 24, and a the final print result is {name: "Julia", age: 24}.
is it different from what you expected? Note that function and return here bring different things.
the reason is: the o passed in the function parameter is the memory address value of the object in the heap. The age attribute of object a is indeed changed by calling o.age = 24 (code in line 7); Line 12 returns the address of parameter o again, and stores {name:"Kath",age:30} in it. Finally, the returned value of b becomes {name:"Kath",age:30}. If you remove line 12, b will return undefined. You can think it over here.
after talking about the basic concept of data type, continue to the next part, how to detect data type, which is also a more important problem.
Data type detection
data type detection is also a common problem in the interview process, such as: how to judge whether it is an array? Write a piece of code to judge various data types of JavaScript, and so on. There are many similar topics, and we often use them in the process of writing code.
during the interview, there are some answers, such as "judge by typeof", and then there are no other answers, but such answers can not satisfy the interviewer, because he wants to investigate the depth of your understanding of JS data types, so the first thing to do is to know the judgment methods of various data types, and then summarize them, Give the interviewer a satisfactory answer.
there are actually many methods for judging data types, such as typeof and instanceof. The following focuses on three data type detection methods that are often encountered in work.
The first judgment method: typeof
This is a common method, so let's quickly review this method through a piece of code.
typeof 1 // 'number' typeof '1' // 'string' typeof undefined // 'undefined' typeof true // 'boolean' typeof Symbol() // 'symbol' typeof null // 'object' typeof [] // 'object' typeof {} // 'object' typeof console // 'object' typeof console.log // 'function'
you can see that the first six are basic data types, but why is the sixth null typeof 'object'? Here I want to emphasize to you that although typeof null will output object, this is only a long-standing Bug in JS. It does not mean that null is a reference data type, and null itself is not an object. Therefore, null returns a problematic result after typeof and cannot be used as a method to judge null. If you need to judge whether it is null in the if statement, just use '= = = null'.
in addition, it should be noted that if the data type object is referenced and judged by typeof, except that function will be judged as OK, the rest are 'object', which cannot be judged.
The second judgment method: instanceof
you must have heard of the instanceof method. If we create a new object, then the new object is the object inherited from its prototype chain. Through instanceof, we can judge whether the object is the object generated by the previous constructor, so we can basically judge the data type of the new object. Let's take a look at the code.
let Car = function() {} let benz = new Car() benz instanceof Car // true let car = new String('Mercedes Benz') car instanceof String // true let str = 'Covid-19' str instanceof String // false
the above is the general process of judging data types by instanceof method. How should you write if you want to implement an underlying implementation of instanceof yourself? Look at the code below.
function myInstanceof(left, right) { // Here, use typeof to judge the basic data type. If yes, return false directly if(typeof left !== 'object' || left === null) return false; // getProtypeOf is the API of the Object object Object, which can get the prototype Object of the parameter let proto = Object.getPrototypeOf(left); while(true) { //Loop down until you find the same prototype object if(proto === null) return false; if(proto === right.prototype) return true;//If the same prototype object is found, return true proto = Object.getPrototypeof(proto); } } // Verify whether the myInstanceof implemented by yourself is OK console.log(myInstanceof(new Number(123), Number)); // true console.log(myInstanceof(123, Number)); // false
now that we know two methods to judge data types, what are the differences between them? The following two points are summarized:
- instanceof can accurately judge complex reference data types, but it cannot correctly judge basic data types;
- typeof also has disadvantages. Although it can judge the basic data type (except null), it can not judge other types of reference data types except function type.
The third judgment method: Object.prototype.toString
toString() is the prototype method of Object. Calling this method can uniformly return strings in the format of "[object Xxx]", where Xxx is the type of Object. For Object objects, directly call toString() to return [object Object]; For other objects, you need to call through call to return the correct type information. Take a look at the code.
Object.prototype.toString({}) // "[object Object]" Object.prototype.toString.call({}) // The result is the same as above. It is ok to add call Object.prototype.toString.call(1) // "[object Number]" Object.prototype.toString.call('1') // "[object String]" Object.prototype.toString.call(true) // "[object Boolean]" Object.prototype.toString.call(function(){}) // "[object Function]" Object.prototype.toString.call(null) //"[object Null]" Object.prototype.toString.call(undefined) //"[object Undefined]" Object.prototype.toString.call(/123/g) //"[object RegExp]" Object.prototype.toString.call(new Date()) //"[object Date]" Object.prototype.toString.call([]) //"[object Array]" Object.prototype.toString.call(document) //"[object HTMLDocument]" Object.prototype.toString.call(window) //"[object Window]"
as can be seen from the above code, Object.prototype.toString.call() can well judge the reference type, and even distinguish document from window.
however, when writing judgment conditions, you must pay attention to that the format of the unified string returned by using this method is "[object Xxx]", and the "Xxx" in the string here should be capitalized (Note: the lowercase returned by using typeof). Pay more attention here.
then, let's implement a global general data type judgment method to deepen our understanding. The code is as follows.
function getType(obj){ let type = typeof obj; if (type !== "object") { // Type of judgment is performed first. If it is a basic data type, it is returned directly return type; } // If the return result of typeof is object, make the following judgment to return the regular result return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1'); // Notice a space in the middle of the regular } /* In code verification, you need to pay attention to case. Which are typeof judgments and which are toString judgments? Think about it */ getType([]) // "Array" typeof [] is an object, so toString returns getType('123') // "string" typeof returns directly getType(window) // "Window" toString return getType(null) // "Null" is capitalized, typeof null is an object, which needs toString to judge getType(undefined) // "undefined" typeof returns directly getType() // "undefined" typeof returns directly getType(function(){}) // "function" typeof can judge, so the first letter is lowercase getType(/123/g) //"RegExp" toString returns
here, the three methods of data type detection are introduced. Finally, the sample code is given. I hope you can learn and use them by comparison, and constantly deepen your memory, so that you won't be in a hurry when you encounter problems. If you can't remember it over and over again, you can look back and over again and consolidate it until you can understand all the above codes, and strengthen your memory of several special problems, so that there will be no problem doing similar problems in the future.
Data type conversion
in daily business development, we often encounter the problem of JavaScript data type conversion. Sometimes we need to take the initiative to perform forced conversion, and sometimes JavaScript will perform implicit conversion. We need to pay more attention to implicit conversion.
So what will be involved in this part? Let's take a look at a piece of code to understand the general situation.
'123' == 123 // false or true? '' == null // false or true? '' == 0 // false or true? [] == 0 // false or true? [] == '' // false or true? [] == ![] // false or true? null == undefined // false or true? Number(null) // Back to what? Number('') // Back to what? parseInt(''); // Back to what? {}+10 // Back to what? let obj = { [Symbol.toPrimitive]() { return 200; }, valueOf() { return 300; }, toString() { return 'Hello'; } } console.log(obj + 200); // How much does it print out here?
the above 12 questions are not unfamiliar to you. They basically cover some situations that we are easy to miss, that is, the methods of forced conversion and implicit conversion often encountered in data type conversion. Next, I will explain in detail around the two conversion methods of data type, hoping to provide some reference.
Cast type
forced type conversion methods include Number(), parseInt(), parseFloat(), toString(), String(), Boolean(). These methods are similar. It is easy to understand from the literal meaning. They are all forced to convert data types through their own methods. Here are some examples to illustrate in detail.
in the above code, the result on line 8 is 0, the result on line 9 is also 0, and the result on line 10 is NaN. These are obvious cast types because Number() and parseInt() are used.
in fact, the principles of the above mandatory type conversions are roughly the same. Here are two representative methods to explain.
Cast rule for Number() method
- If it is a Boolean value, true and false are converted to 1 and 0 respectively;
- If it is a number, return itself;
- If null, return 0;
- If undefined, NaN is returned;
- If it is a string, follow the following rules: if the string contains only numbers (or hexadecimal digit string starting with 0X / 0x, positive and negative signs are allowed), convert it to decimal; If the string contains valid floating-point format, convert it to floating-point value; If it is an empty string, convert it to 0; If the string is not in the above format, NaN is returned;
- If it is a Symbol, an error is thrown;
- If it is an Object and [Symbol.toPrimitive] is deployed, call this method; otherwise, call the valueOf() method of the Object, and then convert the returned value according to the previous rules; If the result of the conversion is NaN, call the toString() method of the Object and convert again in the previous order to return the corresponding value (the Object conversion rules will be described in detail below).
The following is a code to illustrate the above rules.
Number(true); // 1 Number(false); // 0 Number('0111'); //111 Number(null); //0 Number(''); //0 Number('1a'); //NaN Number(-0X11); //-17 Number('0X11') //17
among them, common examples of Number conversion are listed respectively. They will convert the corresponding non digital type into digital type, while some can't be converted into digital, and finally can only output NaN results.
Cast rule for Boolean() method
the rule of this method is: except undefined, null, false, '', 0 (including + 0, - 0), NaN is converted to false, others are true.
this rule should be well understood. Without so many rules, we still form cognition through code, as shown below.
Boolean(0) //false Boolean(null) //false Boolean(undefined) //false Boolean(NaN) //false Boolean(1) //true Boolean(13) //true Boolean('12') //true
Implicit type conversion
implicit type conversion will occur for operations through logical operators (& &, ||,!), operators (+, -, *, /), relational operators (>, <, < =, > =), equality operators (= =) or if/while conditions. If two data types are different. Here you need to focus on it, because it is hidden and easy to be ignored.
the following focuses on the implicit conversion rules of "= =" and "+" symbols, which are often used in daily life.
Implicit type conversion rule for '= ='
- If the types are the same, no type conversion is required;
- If one of the operation values is null or undefined, the other operator must be null or undefined to return true, otherwise it will return false;
- If one of them is of Symbol type, false is returned;
- If the two operation values are of type string and number, the string will be converted to number;
- If an operation value is boolean, it is converted to number;
- If an operation value is object and the other party is string, number or symbol, the object will be converted to the original type for judgment (call the valueOf/toString method of object for conversion).
If we directly memorize these theories, it will be a little confused. We'd better look at the code directly, so it's easier to understand, as shown below.
null == undefined // true rule 2 null == 0 // false rule 2 '' == null // false rule 2 '' == 0 // true rule 4: the string is implicitly converted to Number and then compared '123' == 123 // true rule 4: the string is implicitly converted to Number and then compared 0 == false // True e rule Boolean is implicitly converted to Number and then compared 1 == true // True e rule Boolean is implicitly converted to Number and then compared var a = { value: 0, valueOf: function() { this.value++; return this.value; } }; // Note that here a can be equal to 1, 2 and 3 console.log(a == 1 && a == 2 && a ==3); //true f rule Object implicit conversion // Note: however, after 3 times of execution, re execution of a==3 or the previous number is false, because value has been added, which should be noted here
After reading the above code and comments against this rule, you can go back and do the 12 problems before explaining "data type conversion". Is it easy to solve?
Implicit type conversion rule for '+'
The '+' sign operator can be used not only for number addition, but also for string splicing. Only when both sides of the '+' sign are numbers, the addition operation is performed; If both sides are strings, they are spliced directly without implicit type conversion.
in addition to the above more conventional cases, there are some special rules, as shown below.
- If one of them is a string and the other is undefined, null or boolean, call the toString() method for string splicing; If it is a pure object, array, regular, etc., the conversion method of the calling object will have priority by default (which will be specifically introduced in the next lecture), and then splicing.
- If one of them is a number and the other is undefined, null, Boolean or number, it will be converted into a number for addition. For the object, refer to the previous rule
- If one of them is a string and the other is a number, they are spliced according to the string rules.
The following is to understand the above rules in combination with the code, as shown below.
1 + 2 // 3 general conditions '1' + '2' // '12' general situation // Let's take a look at the special situation '1' + undefined // "1 undefined" rule 1, undefined conversion string '1' + null // "1null" rule 1, null conversion string '1' + true // "1true" rule 1, true conversion string '1' + 1n // '11' compare the special string and BigInt, and convert BigInt to string 1 + undefined // NaN rule 2, undefined conversion number addition NaN 1 + null // 1 Rule 2, null converted to 0 1 + true // 2 rule 2, true is converted to 1, and the sum of the two is 2 1 + 1n // Error: BigInt and Number types cannot be mixed and added directly '1' + 3 // '13' rule 3, string splicing
on the whole, if there is a string in the data, JavaScript type conversion is more likely to convert to a string, because it can be seen in the third rule that the last returned in the process of adding a string and a number is a string, which needs attention here.
Object conversion rules
For the rule of object conversion, the built-in [ToPrimitive] function will be called first. The rule logic is as follows:
- If the Symbol.toPrimitive method is deployed, call first and then return;
- Call valueOf(). If it is converted to a basic type, it returns;
- Call toString(). If it is converted to a basic type, it returns;
- If no basic type is returned, an error will be reported.
It's a bit obscure to understand directly, or just look at the code. You can type it again on the console to deepen your impression.
var obj = { value: 1, valueOf() { return 2; }, toString() { return '3' }, [Symbol.toPrimitive]() { return 4 } } console.log(obj + 1); // Output 5 // Because there is Symbol.toPrimitive, this is implemented first; If the code Symbol.toPrimitive is deleted, execute valueOf and the print result is 3; If valueOf is also removed, toString is called to return '31' (string splicing) // Look at two special case s: 10 + {} // "10 [object]", note: {} will call valueOf by default, which is {}, not the basic type. Continue the conversion, call toString and return the result "[object]", so conduct '+' operation with 10, follow the string splicing rules, and refer to rule C of '+' [1,2,undefined,4,5] + 10 // "1,2,, 4510". Note that [1,2,undefined,4,5] will call valueOf first by default. The result is still this array. It is not the basic data type to continue the conversion, or toString will be called to return "1,2,, 4,5", and then operate with 10. Still follow the string splicing rules, refer to rule 3 of '+'
summary
We have learned about data types from three aspects. Let's review them as a whole.
- Basic concept of data type: This is a knowledge point that must be mastered as the basis for in-depth understanding of JavaScript.
- Methods for judging data types: typeof and instanceof, as well as judging data types of Object.prototype.toString and handwritten instanceof code fragments, which are often encountered in daily development, so you need to master them well.
- Data type conversion methods: two data type conversion methods. Pay more attention to implicit conversion in daily code writing. If you don't understand it in place, it is easy to cause bug s in the coding process and get some unexpected results.