Introduction to the

As we all know, JavaScript is a weakly typed language and does not type enforce variables, which can be changed to any type of value at any time. This creates both flexibility and uncontrollability, which can lead to strange bugs. Today this article mainly from JS data type, JS data type judgment method, JS data type mutual conversion of three aspects, let you thoroughly understand JS data type.

Hit me if you don’t understand data types after reading this article. All right, let’s get started!

JS data type

In JS, data types are divided into basic data types and reference data types. Basic data types include Number, String, Boolean, Null, Undefined, Symbol and BigInt. Reference data types include Object, Date, Error, Function, and RegExp.

I believe that the JS data type you are already familiar with the heart, the author will not be detailed examples, here I only emphasize a point is memory space storage.

Basic data types are held in stack memory because they take up small space, are fixed in size, are accessed by value, and are frequently used data.

Reference data types are stored in heap memory because they take up large and variable amounts of memory. If stored on the stack, the performance of the program will be affected. The reference data type stores a pointer on the stack to the starting address of the entity in the heap. When the interpreter looks for a reference value, it first retrieves its address in the stack and then retrieves the entity from the heap.

Let me use a simple example to explain clearly.

let a = 1;
let b = a; // Creates a new memory space on the stack and assigns a value of 1.
b = 2; // b changes to 2 without affecting the value of A.
console.log(a, b);  // Output 1, 2

let c = {num: 1};
let d = c; // d is the same address in the heap.
d.num = 2; // So if d changes, c will also change.
console.log(c.num, d.num); // Output 2 2
Copy the code

How can we make reference data types assign values like primitive data types? Here involves deep copy and shallow copy, behind the author will give a special article to detail.

JS data type judgment method

Say that JS data type, next is JS data type judgment method. There are many ways to determine the JS data type, Common typeof, instanceof, Object. The prototype. ToString. The call (), constructor. The name, constructor. The toString (). The indexOf () although are judging data types each have each again Since the characteristics of.

typeof

  1. typeofGets a lowercase string type.
  2. typeofIn addition to determining basic data typesnullWill judge intoobjectEverything else is accurate.
  3. typeofDetermine the reference data type exceptfunctionWill judge intofunctionEverything else will be judgedobject.

Here I use examples to explain to you, perceptual interested partners can copy to the browser to take a look oh.

function User(name, age) {
  this.name = name;
  this.age = age;
}
const user = new User("randy".24);

// Typeof gets lowercase data types
const typeOfTest = () = > {
  console.log("typeof 1:".typeof 1); //number
  console.log("typeof a:".typeof "a"); //string
  console.log("typeof false:".typeof false); //boolean
  console.log("typeof undefined:".typeof undefined); //undefined
  console.log("typeof Symbol():".typeof Symbol()); //symbol
  console.log("typeof 9007199254740991n:".typeof 9007199254740991n); //bigint
  console.log("typeof BigInt('9007199254740991'):".typeof BigInt("9007199254740991")); //bigint

  // Typeof NaN is number
  console.log("typeof NaN:".typeof NaN); //number
  
  // Typeof identifies basic data types as object except for null.
  console.log("typeof null:".typeof null); //object

  // all reference data types except function are treated as object.
  console.log("typeof new Number(1):".typeof new Number(1)); //object
  console.log("typeof new String('a'):".typeof new String("a")); //object
  console.log("typeof new Boolean(false):".typeof new Boolean(false)); //object
  console.log("typeof new Date():".typeof new Date()); //object
  console.log("typeof []:".typeof []); //object
  console.log("typeof new Array(10):".typeof new Array(10)); //object
  console.log("Typeof new Error(' custom Error '):".typeof new Error("Custom error")); //object
  console.log("typeof user:".typeof user); //object
  console.log("typeof User:".typeof User); //function
  console.log("typeof new RegExp('[0-9]? ').".typeof new RegExp('[0-9]? ')); //object
  console.log("typeof /[0-9]? / :".typeof/ [0-9]?/); //object }; typeOfTest();Copy the code

instanceof

  1. instanceofGets either true or false.
  2. instanceofOnly reference data types and custom reference data types can be determined. Basic data types cannot be determined.

Here I use examples to explain to you, perceptual interested partners can copy to the browser to take a look oh.

function User(name, age) {
  this.name = name;
  this.age = age;
}
const user = new User("randy".24);

const instanceofTest = () = > {
  console.log("1 instanceof Number:".1 instanceof Number); //false
  console.log("a instanceof String:"."a" instanceof String); //false
  console.log("true instanceof Boolean:".true instanceof Boolean); //false
  console.log("null instanceof Object:".null instanceof Object); //false
  console.log("undefined instanceof Object:".undefined instanceof Object); //false
  console.log("Symbol() instanceof Symbol:".Symbol(a)instanceof Symbol); //false
  console.log("9007199254740991n instanceof BigInt:".9007199254740991n instanceof BigInt); //false
  console.log("BigInt('9007199254740991') instanceof BigInt:".BigInt("9007199254740991") instanceof BigInt); //false

  // Both reference data types and custom reference data types can be judged correctly
  console.log("user instanceof User:", user instanceof User); //true
  console.log("new Number(1) instanceof Number:".new Number(1) instanceof Number); //true
  console.log("new String('a') instanceof String:".new String("a") instanceof String); //true
  console.log("new Boolean(false) instanceof Boolean:".new Boolean(false) instanceof Boolean); //true
  console.log("new Date() instanceof Date:".new Date(a)instanceof Date); //true
  console.log("[] instanceof Array:"And []instanceof Array); //true
  console.log("new Array(10) instanceof Array:".new Array(10) instanceof Array); //true
  console.log("User instanceof Function:", User instanceof Function); //true
  console.log("New Error(' custom Error ') instanceof Error:".new Error("Custom error") instanceof Error); //true
  console.log("new RegExp('[0-9]? ') instanceof RegExp:".new RegExp("[0-9]?") instanceof RegExp); //true
  console.log(/ [0-9]?" / instanceof RegExp:"./ [0-9]? / instanceof RegExp); //true
};

instanceofTest();
Copy the code

Instanceof’s internal working mechanism is to determine whether a prototype of that type can be found in its prototype chain. Here’s how it works. Here will be involved in the prototype and prototype chain related knowledge, if you do not understand, it does not matter, the author will write a special article to explain the prototype and prototype chain.

const instance_of_test = (leftVaule, rightVaule) = > { 
    let rightProto = rightVaule.prototype; // Take the prototype value of the right expression
    leftVaule = leftVaule.__proto__; // Take the __proto__ value of the left expression
    while (true) {
    	if (leftVaule === null) {
            return false;	
        }
        if (leftVaule === rightProto) {
            return true;	
        } 
        leftVaule = leftVaule.__proto__ 
    }
}
Copy the code

Since Instanceof works by looking through a chain of prototypes, the following example is also true.

function User(name, age) {
  this.name = name;
  this.age = age;
}
const user = new User("randy".24);

const instanceofTest2 = () = > {
  console.log("user instanceof Object:", user instanceof Object); //true
  console.log("new Number(1) instanceof Object:".new Number(1) instanceof Object); //true
  console.log("new String('a') instanceof Object:".new String("a") instanceof Object); //true
  console.log("new Boolean(false) instanceof Object:".new Boolean(false) instanceof Object); //true
  console.log("new Date() instanceof Object:".new Date(a)instanceof Object); //true
  console.log("[] instanceof Object:"And []instanceof Object); //true
  console.log("new Array(10) instanceof Object:".new Array(10) instanceof Object); //true
  console.log("User instanceof Object:", User instanceof Object); //true
  console.log("New Error(' custom Error ') instanceof Object:".new Error("Custom error") instanceof Object); //true
  console.log("new RegExp('[0-9]? ') instanceof Object:".new RegExp("[0-9]?") instanceof Object); //true
  console.log(/ [0-9]?" / instanceof Object:"./ [0-9]? / instanceof Object); //true
};

instanceofTest2();
Copy the code

Object.prototype.toString.call()

  1. Object.prototype.toString.call()Access is[object xxx]String, we can passslice(7, -1)Get the real data type (uppercase) from XXX.
  2. Object.prototype.toString.call()Can get js basic data type and reference data type. But you cannot determine the data type of the custom object.

Here I use examples to explain to you, perceptual interested partners can copy to the browser to take a look oh.

function User(name, age) {
  this.name = name;
  this.age = age;
}
const user = new User("randy".24);

const toStringCallTest = () = > {
  // All basic data types can be correctly judged
  console.log(
    "Object.prototype.toString.call(1):".Object.prototype.toString.call(1));//[object Number]
  console.log(
    "Object.prototype.toString.call('a'):".Object.prototype.toString.call("a"));//[object String]
  console.log(
    "Object.prototype.toString.call(false):".Object.prototype.toString.call(false));//[object Boolean]
  console.log(
    "Object.prototype.toString.call(null):".Object.prototype.toString.call(null));//[object Null]
  console.log(
    "Object.prototype.toString.call(undefined):".Object.prototype.toString.call(undefined));//[object Undefined]
  console.log(
    "Object.prototype.toString.call(Symbol()):".Object.prototype.toString.call(Symbol()));// [object Symbol]
  console.log(
    "Object.prototype.toString.call(12312321324234234234234n):".Object.prototype.toString.call(12312321324234234234234n));// [object BigInt]
  console.log(
    "Object.prototype.toString.call(BigInt('12312321324234234234234')):".Object.prototype.toString.call(BigInt("12312321324234234234234")));// [object BigInt]

  // The custom reference data type cannot be determined
  console.log(
    "Object.prototype.toString.call(user):".Object.prototype.toString.call(user)
  ); //[object object] returns object instead of User

  // Reference data types can be correctly determined
  console.log(
    "Object.prototype.toString.call(new Number(1)):".Object.prototype.toString.call(new Number(1)));//[object Number]
  console.log(
    "Object.prototype.toString.call(new String('a')):".Object.prototype.toString.call(new String("a")));//[object String]
  console.log(
    "Object.prototype.toString.call(new Boolean(false)):".Object.prototype.toString.call(new Boolean(false)));//[object Boolean]
  console.log(
    "Object.prototype.toString.call(new Date()):".Object.prototype.toString.call(new Date()));//[object Date]
  console.log(
    "Object.prototype.toString.call([]):".Object.prototype.toString.call([])
  ); //[object Array]
  console.log(
    "Object.prototype.toString.call(new Array(10)):".Object.prototype.toString.call(new Array(10)));//[object Array]
  console.log(
    "Object.prototype.toString.call(User):".Object.prototype.toString.call(User)
  ); //[object Function]
  console.log(
    "Is the Object. The prototype. ToString. Call (new Error (' custom Error) :".Object.prototype.toString.call(new Error("Custom error")));//[object Error]
  console.log(
    "Object.prototype.toString.call(new RegExp('[0-9]? '))".Object.prototype.toString.call(new RegExp("[0-9]?")));//[object RegExp]
  console.log(
    "Object.prototype.toString.call(/[0-9]? /)".Object.prototype.toString.call(/ [0-9]? /));//[object RegExp]
};

toStringCallTest();
Copy the code

We can use the Slice (7, -1) method to retrieve the data type once, for example

Object.prototype.toString.call(new Error("Custom error")).slice(7, -1); / / output Error
Copy the code

constructor.name

  1. Gets the uppercase string type.
  2. The object constructor. The nameYou can get both basic and reference data types and custom reference data types.
  3. becausenull,undefinedThere is noconstructorSo you can’t judge.
  4. Because of the objectconstructorcanchange, so the judgment may not be accurate, need to pay special attention to. We’ll give you an example.

Here I use examples to explain to you, perceptual interested partners can copy to the browser to take a look oh.

function User(name, age) {
  this.name = name;
  this.age = age;
}
const user = new User("randy".24);

const constructorNameTest = () = > {// Basic data type
  console.log("(1).constructor.name:", (1).constructor.name); //Number
  console.log("(a).constructor.name:"."a".constructor.name); //String
  console.log("(false).constructor.name:".false.constructor.name); //Boolean
  // console.log("null.constructor.name:", null.constructor.name); / / an error
  // console.log("undefined.constructor.name:", undefined.constructor.name); / / an error
  console.log("Symbol().constructor.name:".Symbol().constructor.name); //Symbol
  console.log(
    "(12312321324234234234234n).constructor.name:".12312321324234234234234n.constructor.name
  ); //BigInt
  console.log(
    "BigInt('12312321324234234234234').constructor.name:".BigInt("12312321324234234234234").constructor.name
  ); //BigInt

  // Customize the reference data type
  console.log("user.constructor.name:", user.constructor.name); //User

  // Reference the data type
  console.log(
    "new Number(1).constructor.name:".new Number(1).constructor.name
  ); //Number
  console.log(
    "new String('a').constructor.name:".new String("a").constructor.name
  ); //String
  console.log(
    "new Boolean(false).constructor.name:".new Boolean(false).constructor.name
  ); //Boolean
  console.log(
    "new Date().constructor.name:".new Date().constructor.name
  ); //Date
  console.log("[].constructor.name:", [].constructor.name); //Array
  console.log(
    "new Array().constructor.name:".new Array().constructor.name
  ); //Array
  console.log("User.constructor.name:", User.constructor.name); //Function
  console.log(
    "New Error(' custom Error ').constructor.name:".new Error("Custom error").constructor.name
  ); //Error
  console.log(/ [0-9]?" /.constructor.name"./ [0-9]? /.constructor.name); //RegExp
  console.log(
    "new RegExp('[0-9]? ').constructor.name".new RegExp("[0-9]?").constructor.name
  ); //RegExp
};

constructorNameTest();
Copy the code

Since the constructor of an object can be changed, we use constructive. name to determine the data type to pay attention to whether the constructor has been changed. So let me give you an example.

const num = new Number(1);
console.log("num.constructor.name:", num.constructor.name); / / output Number

function Person() {}
/ / change the constructor
num.constructor = Person;
console.log("num.constructor.name:", num.constructor.name); // Output Person so if constructor is changed it is not accurate.
Copy the code

constructor.toString().indexOf()

Constructor is also used in this way, similar to constructor.name. The idea is to convert the constructor to a string and then see if it contains a type string. (1).constructive.toString () output function Number() {[native code]}, then use indexOf().

  1. Retrieves either a positive number (index) or -1.
  2. constructor.toString().indexOf()You can get both basic and reference data types and custom reference data types.
  3. becausenull,undefinedThere is noconstructorSo you can’t judge.
  4. Because of the objectconstructorcanchange, so the judgment may not be accurate, need to pay special attention to.

Here I use examples to explain to you, perceptual interested partners can copy to the browser to take a look oh.

function User(name, age) {
  this.name = name;
  this.age = age;
}
const user = new User("randy".24);

const constructorTest = () = > {console.log(new Number(1).constructor.toString()); //function Number() { [native code] }

  // Basic data type
  console.log(
    "(1).constructor.toString().indexOf('Number') > -1:",
    (1).constructor.toString().indexOf("Number") > -1
  ); //true
  console.log(
    "(a).constructor.toString().indexOf('String') > -1:"."a".constructor.toString().indexOf("String") > -1
  ); //true
  console.log(
    "(false).constructor.toString().indexOf('Boolean') > -1:".false.constructor.toString().indexOf("Boolean") > -1
  ); //true
  // console.log(
  // "null.constructor.toString().indexOf('Null') > -1:",
  // null.constructor.toString().indexOf("Null") > -1
  / /); / / an error
  // console.log(
  // "undefined.constructor.toString().indexOf('Undefined') > -1:",
  // undefined.constructor.toString().indexOf("Undefined") > -1
  / /); / / an error
  console.log(
    "Symbol().constructor.toString().indexOf('Symbol') > -1:".Symbol().constructor.toString().indexOf("Symbol") > -1
  ); //true
  console.log(
    "12312321324234234234234n.constructor.toString().indexOf('BigInt') > -1:".12312321324234234234234n.constructor.toString().indexOf("BigInt") > -1
  ); //true
  console.log(
    "BigInt('12312321324234234234234').constructor.toString().indexOf('BigInt') > -1:".BigInt("12312321324234234234234")
      .constructor.toString()
      .indexOf("BigInt") > -1
  ); //true

  // Customize the reference data type
  console.log(
    'user.constructor.toString().indexOf("User") > -1:',
    user.constructor.toString().indexOf("User") > -1
  ); //true

  // Reference the data type
  console.log(
    "new Error().constructor.toString().indexOf('Error') > -1:".new Error().constructor.toString().indexOf("Error") > -1
  ); //true
  console.log(
    "new Date().constructor.toString().indexOf('Date') > -1:".new Date().constructor.toString().indexOf("Date") > -1
  ); //true
  console.log(
    "[].constructor.toString().indexOf('Array') > -1:",
    [].constructor.toString().indexOf("Array") > -1
  ); //true
  console.log(
    "new Array().constructor.toString().indexOf('Array') > -1:".new Array().constructor.toString().indexOf("Array") > -1
  ); //true
  console.log(
    "User.constructor.toString().indexOf('Function') > -1:",
    User.constructor.toString().indexOf("Function") > -1
  ); //true
  console.log(
    "new Number(1).constructor.toString().indexOf('Number') > -1:".new Number(1).constructor.toString().indexOf("Number") > -1
  ); //true
  console.log(
    "new String(a).constructor.toString().indexOf('String') > -1:".new String("a").constructor.toString().indexOf("String") > -1
  ); //true
  console.log(
    "new Boolean(false).constructor.toString().indexOf('Boolean') > -1:".new Boolean(false).constructor.toString().indexOf("Boolean") > -1
  ); //true
  console.log(
    / [0-9]?" /.constructor.toString().indexOf('RegExp') > -1"./ [0-9]? /.constructor.toString().indexOf("RegExp") > -1
  ); //true
  console.log(
    "new RegExp('[0-9]? ').constructor.toString().indexOf('RegExp') > -1".new RegExp("[0-9]?").constructor.toString().indexOf("RegExp") > -1
  ); //true
};

constructorTest();
Copy the code

As with constructive.name, we use constructive.toString ().indexof () to determine the data type because the object’s constructor can be changed. So let me give you an example.

const num2 = new Number(1);
console.log("num2.constructor.toString().indexOf('Number') > -1:", num2.constructor.toString().indexOf('Number') > -1); / / output true

function Person() {}
/ / change the constructor
num2.constructor = Person;
console.log("num2.constructor.toString().indexOf('Number') > -1:", num2.constructor.toString().indexOf('Number') > -1); // Output false so if constructor is changed it is not accurate.
Copy the code

JS data type conversion

JS data type conversion is divided into other values to Boolean type conversion, other values to string type conversion, other values to numeric type conversion

Conversion of other values to Boolean values

The global methods Boolean() or New Boolean() can convert other values to Booleans.

  1. Except for these false values:undefined,null,false,0,+ 0,0,NaN,""The result of the Boolean cast isfalse. Logically, anything outside the list of false values should be true.
  2. SymbolCan be cast to a Boolean value (both explicit and implicit results are true).
const convertBooleanTest = () = > {
  console.log("Boolean(1):".Boolean(1)); //true
  console.log("Boolean('a'):".Boolean('a')); //true
  console.log("Boolean(Symbol()):".Boolean(Symbol())); //true
  console.log("Boolean(' '):".Boolean("")); //true

  console.log("Boolean(false):".Boolean(false)); //false
  console.log("Boolean(undefined):".Boolean(undefined)); //false
  console.log("Boolean(null):".Boolean(null)); //false
  console.log("Boolean(0):".Boolean(0)); //false
  console.log("Boolean(-0):".Boolean(-0)); //false
  console.log("Boolean(+0):".Boolean(+0)); //false
  console.log("Boolean(NaN):".Boolean(NaN)); //false
  console.log("Boolean(''):".Boolean("")); //false
};

convertBooleanTest();
Copy the code

Conversion of other values to string types

The global method String() or new String() can convert other values to strings. Or use an implicit conversion via + “”.

  1. Null and Undefined. Null is converted to “Null” and Undefined to “Undefined”.
  2. Boolean type, true to “true”, false to “false”.
  3. A value of type Number converts a string value directly.
  4. Values of type Symbol are converted directly, but only explicit casts are allowed. Using implicit casts produces errors.
  5. For objects, toString() is called to return internal attributes [[Class]]Values, such as[object Object]. If the object has a customtoString()Method, and returns something other than a primitive data typevalueOf()Methods. ifvalueOf()Method returns an error if it does not yet return a primitive data typeUncaught TypeError: Cannot convert object to primitive valueIf it is a basic data type, the value is converted to String and printed.
const convertStringTest = () = > {
  console.log("String(null):".String(null)); // null
  console.log("String(undefined):".String(undefined)); // undefined
  console.log("String(1):".String(1)); / / 1
  console.log("String(false):".String(false)); // false
  console.log("String(1112323212424234n):".String(1112323212142423114n)); / / 1112323212142423114
  console.log("String(Symbol()):".String(Symbol())); //Symbol()
  // console.log("Symbol() + '':", Symbol() + ""); / / complains
  console.log("String({}):".String({})); //[object Object]
  
  // The Error constructor overrides the toString() method
  console.log(
    "String(new Error(' custom Error ')):".String(new Error("Custom error")));//Error: indicates a custom Error
};

convertStringTest();
Copy the code

Let’s take a look at the process of converting object types to strings. Interested partners can comment the return values separately to test.

const converStringTest2 = () = > {
  function Animal(name) {
    this.name = name;
  }
  // Override the toString method
  Animal.prototype.toString = function () {
    console.log("ToString called first");
    return { name: "toString" }; // Continue calling the valueOf method if it does not return a basic data type
    // return "toString method return value "; // Returns a primitive type and does not call valueOf
  };
  // Override the valueOf method
  Animal.prototype.valueOf = function () {
    console.log("Called after valueOf");
    // return { name: "valueOf" }; // Return the basic data type, so an error is reported
    return "Return valueOf the valueOf method"; // Return the basic data type directly
  };
  
  const dog = new Animal("dog");
  console.log("String(dog):".String(dog));
  
  // Outputs the returns of toString calls, valueOf calls, and valueOf methods in sequence
}

converStringTest2()
Copy the code

Conversion of other values to numeric types

The global method Number() or new Number() converts a string to a Number.

  1. A value of undefined is converted to NaN.
  2. A value of type Null is converted to 0.
  3. Boolean values, true to 1 and false to 0.
  4. String values are converted as if usingNumber()Function to convert to NaN if it contains a non-numeric value, with an empty string of 0.
  5. Accuracy is lost when BingInt is converted to Number.
  6. Symbol values cannot be converted to numbers (both explicit and implicit produce errors).
  7. Is called first for object typesvalueOf()Methods. If no primitive type value is returned, the call continuestoString(). ifvalueOf()toString()None returns a value of the base type, an error is reportedUncaught TypeError: Cannot convert object to primitive value. If a value of the base data type is returned, it is converted to the Number type and printed.
const convertNumberTest = () = > {
  console.log("Number(undefined):".Number(undefined)); // NaN
  console.log("Number(null):".Number(null)); / / 0
  console.log("Number(true):".Number(true)); / / 1
  console.log("Number(false):".Number(false)); / / 0
  console.log("Number(123):".Number("123")); / / 123
  console.log("Number('123a'):".Number("123a")); // NaN
  console.log("Number(''):".Number("")); / / 0
  console.log("Number(1112323212424234n):".Number(1112323212142423114n)); / / 1112323212142423200
  // console.log("Number(Symbol()):", Number(Symbol())); / / complains
};
Copy the code

Let’s take a look at the process of converting object types to strings. Interested partners can comment the return values separately to test.

function User(name, age) {
  this.name = name;
  this.age = age;
}
const user = new User("randy".24);

const convertNumberTest2 = () = > {
  1 / / examples
  console.log("Number(user):".Number(user)); //NaN
  // Calling valueOf() first returns User {name: 'randy', age: 24} instead of calling toString()
  console.log("user.valueOf():", user.valueOf()); //User { name: 'randy', age: 24 }
  // The toString call returns object object, but turns the string into NaN, so the return value is NaN.
  // An error is reported if toString() is not a basic data type
  console.log("user.toString():", user.toString()); //[object Object]

  2 / / examples
  function Animal(name) {
    this.name = name;
  }
  Animal.prototype.toString = function () {
    console.log("Call after toString");
    // return { name: "toString" }; // An error occurs when a reference data type is returned
    // return "toString method return value "; // Is a basic data type but cast to Number to get NaN
    return 123; Return 123 directly for the basic data type
  };
  Animal.prototype.valueOf = function () {
    console.log("ValueOf is called first");
    return { name: "valueOf" }; // Continue to call the toString method if it is not a basic data type
    // return "valueOf method return value "; // Is a basic data type but cast to Number to get NaN
  };
  const dog = new Animal("dog");
  console.log("Number(dog):".Number(dog)); / / 123

  // valueOf is called first, toString is called later, 123 is called
};

convertNumberTest2();
Copy the code

So what’s the logic of calling toString first and calling valueOf first? Don’t worry, I’ll get to that.

ToString valueOf execution principle

  1. Called when the object is outputvalueOf()Method (except that the new Date object calls the toString() method), which returns the original value of the object.
  2. Object is called when the base type is convertedvalueOf()toString()Which method to call first depends mainly on what the object is inclined to convert.
  • If you’re inclined to convert toNumberType, is preferentially calledvalueOf(); If you’re inclined to convert toStringType, is called firsttoString().
  • For example, usingNumber()The transformation is called firstvalueOf()Method, which is called again if valueOf() does not return a primitive typetoString()Method, an error is reported if none of them return a base type.
  • For example, usingString()The transformation is called firstoString()Method, iftoString()No return base type will be called againvalueOf()Method, an error is reported if none of them return a base type.
  • If you haveSymbol.toPrimitiveProperty will only be calledSymbol.toPrimitiveMethod,toString()valueOf()Method will not be called. And this method can only return the basic type, otherwise an error will be reported.

Let’s give an example. Interested partners can comment the return values separately to test.

const toStringValueOfTest = () = > {
  function Animal(name) {
    this.name = name;
  }
  
  Animal.prototype.toString = function () {
    console.log("The toString method");
    return "toString";
  };
  Animal.prototype.valueOf = function () {
    console.log("The valueOf method");
    return "valueOf";
  };

  // With symbol. toPrimitive, toString and valueOf methods are no longer called.
  Animal.prototype[Symbol.toPrimitive] = function () {
    console.log("Symbol. ToPrimitive method");
    return "Symbol.toPrimitive";
  };

  const dog = new Animal("cat");
  console.log(String(dog)); // symbol. toPrimitive Converts the string to get symbol. toPrimitive
  console.log(Number(dog)); // symbol. toPrimitive converts numbers to NaN
  
  // Outputs Symbol. ToPrimitive method, Symbol. ToPrimitive method, Symbol
};

toStringValueOfTest();
Copy the code

extension

ParseInt (), parseFloat(), and Number()

We all know that parseInt(), parseFloat(), and Number() all convert to Number, but what’s the difference?

  1. parseInt(),parseFloat()Parsing strings are allowed to contain non-numeric characters in left-to-right order, stopping if non-numeric characters are encountered. whileNumber()Non-numeric characters are not allowed, otherwise returnsNaN.
  2. ParseInt is rounded, but not rounded. whileparseFloat()andNumber()It’s not going to round.
const parseIntNumberTest = () = > {
  console.log('parseInt("123a"):'.parseInt("123a")); / / 123
  console.log('parseFloat("123a"):'.parseFloat("123a")); / / 123
  console.log(' 'parseInt (" 123.6 ")..parseInt("123.6")); / / 123
  console.log(' 'parseFloat (" 123.6 ")..parseFloat("123.6")); / / 123.6
  console.log('Number("123a"):'.Number("123a")); // NaN
  console.log(' 'Number (" 123.3 ")..Number("123.3")); / / 123.3
};

parseIntNumberTest();
Copy the code

+ – * / % operator

  1. If it’s a + operation, and there are string operands and both are primitive data types, then the string is concatenated directly.
  2. If there are operands that reference the data type, the reference data type is converted to Number before concatenating the string.
  3. If there are no string operands, they are converted to Number for evaluation.
const OperatorTest = () = > {
  // If there are no string operands, they are converted to Number for calculation.
  console.log("true + 2:".true + 2); // true converts the number to 1, so you get 3
  console.log("true - 2:".true - 2); // true converts the number to 1, so -1
  console.log("true / 2:".true / 2); // true converts the number to 1 to get 0.5
  console.log("null + 2:".null + 2); // null converts the number to 0 so you get 2
  console.log("undefined + 2:".undefined + 2); // undefined converts the number to NaN, so we get NaN
  
  String concatenation is performed directly if the string operands and the string operands are basic data types.
  console.log('"a" + 2:'."a" + 2); // If there are strings, we will concatenate them, so we get a2
  console.log('"a" + true'."a" + true); // If there is a string, the string is concatenated, so we get atrue

  // If there are operands that reference the data type, convert the reference data type to Number before concatenating the string.
  function Animal(name) {
    this.name = name;
  }
  // here toString will not be called because valueOf already returns the valueOf the base data type.
  Animal.prototype.toString = function () {
    console.log("The toString method");
    return "toString";
  };
  Animal.prototype.valueOf = function () {
    console.log("The valueOf method");
    return 12;
  };
  const dog = new Animal("brid");
  console.log("dog + 2:", dog + 2); // Print the valueOf method and return 12 to calculate 14
  console.log("dog - 2:", dog - 2); // Print the valueOf method and return 12 to calculate 10
  console.log("dog * 2:", dog * 2); // Print the valueOf method and return 12 to calculate 24
  console.log("dog / 2:", dog / 2); // Print the valueOf method and return 12 to calculate 6
  console.log("dog % 2:", dog % 2); // Prints the valueOf method and returns 12 calculated to 0
  console.log("' ha ha '+ dog:"."Ha ha" + dog); // Print the valueOf method and return 12
};

OperatorTest();
Copy the code

The = = operator

  1. Equality comparison between a string and a number, after converting a string to a number.
  2. Equality comparison between other types and Boolean types. After converting a Boolean value to a number, true to 1 and false to 0, other rules apply for comparison.
  3. An equality comparison between null and undefined. The result is true. Comparisons with other values return false values.
  4. Equality comparison always returns false if an operation has a NaN value (NaN itself is not equal to NaN).
  5. Comparison of equality between objects and non-objects. Objects are compared after they become primitive by calling the valueOf or toString abstract operation. By default, toString is called first if toString or valueOf is not overridden, otherwise, valueOf is overridden first.
  6. If both operation values are objects, compare them to see if they refer to the same object. The equality operator returns true if both operands refer to the same object, false otherwise.
const dengyu1Test = () = > {
  console.log("1 = = '1',".1= ="1"); // true
  console.log("true == '1':".true= ="1"); // true is converted to 1, the string '1' is converted to 1, and then compared to true
  console.log("true == 1:".true= =1); // true
  console.log("false == '0':".false= ="0"); // true
  console.log("false == 0:".false= =0); // true
  
  // Bool string to number 1==NaN returns false
  console.log("true == 'true':".true= ="true"); //false
  console.log("false == 'false':".false= ="false"); //false
  console.log("null == undefined:".null= =undefined); //true
  console.log("NaN == NaN:".NaN= =NaN); //false
};
dengyu1Test();
Copy the code

Object and non-object comparison.

const dengyu2Test = () = > {
  function Animal(name) {
    this.name = name;
  }
  Animal.prototype.toString = function () {
    console.log("The toString method");
    return "toString";
  };
  Animal.prototype.valueOf = function () {
    console.log("The valueOf method");
    return 1;
  };
  const dog = new Animal("brid");
  
  console.log("dog == '[object Object]':", dog == "[object Object]"); 
  console.log("dog == true:", dog == true);

  // Output valueOf method, false, valueOf method, true
};
dengyu2Test();
Copy the code

Object to object comparison.

const dengyu3Test = () = > {

  function Animal(name) {
    this.name = name;
  }

  const dog = new Animal("brid");
  
  // Do not point to the same address
  const dog2 = new Animal("brid");
  console.log("dog == dog2:", dog == dog2); //false
  
  // point to the same address
  const dog3 = dog;
  console.log("dog == dog3:", dog == dog3); //true
};
dengyu3Test();
Copy the code

= = = operator

=== does not perform type conversion, first compares the type, returns false, same type comparison value.

const dengyu4Test = () = > {
  console.log("1 = = = 1:".1= = =1); // true
  console.log("1 = = = '1'.".1= = ="1"); // false
  
  function Animal(name) {
    this.name = name;
  }
  const dog = new Animal("brid");
  
  // Do not point to the same address
  const dog2 = new Animal("brid");
  
  // point to the same address
  const dog3 = dog;
  console.log("dog === dog2:", dog === dog2); //false
  console.log("dog === dog3:", dog === dog3); //true
};
dengyu4Test();
Copy the code

&& | |

The && logic and, also called the short-circuit and, finds the first virtual expression in its operands and returns it. A short circuit was used to prevent unnecessary work. If no virtual expression is found, the value of the last expression is returned.

| | logic or also called short circuit or, find the first true value in its operands expressions and returns it. A short circuit was used to prevent unnecessary work. If no truth-value expression is found, the value of the last expression is returned.

So logic and logic or return not true false but the value of some expression.

// output a, console.log("a") returns undefined so return a undefined
console.log(1 && console.log("a") && null && console.log("b") && 2); //a undefined

// No virtual value returns the value of the last item
console.log("" && true && 5); / / 5

// Return the first true value
console.log(null || console.log("a") | |1 || console.log("b")); // a 1

// No true value returns the value of the last item
console.log(undefined || null); //null
Copy the code

Well, about the JS data type, the author has talked about, thank you for your patience to watch.

Afterword.

This article is the author’s personal study notes, if there are fallacies, please inform, thank you! If this article helped you, please give it a thumbs up