1. esType

The original type

In JS, there are seven primitive types:

  • Boolean
  • Null
  • Undefined
  • Number
  • String
  • Symbol
  • BigInt

Primitive types store values; there are no functions to call.

So the question is, why is ‘1’.tostring () correct?

The reason is that in this case, ‘1’ has already been cast to String.

Reference data types: Object (including ordinary Object -Object, Array Object -Array, regular Object -RegExp, Date Object -Date, Math Function -Math, Function Object -Function)

function test(person) {
  person.age = 18
  person = {
    name: 'Andy'.age: 19
  }
  return person
}
const p1 = {
  name: 'sq'.age: 20
}
const p2 = test(p1)
console.log(p1) / / - >?
console.log(p2) / / - >?
Copy the code

Results:

P1: {name: 'sq'.age: 18 }
p2: { name: 'Andy'.age: 19 }
Copy the code

The reason: The person argument in the test function is the memory address of p1. It does change p1 by calling Person. age = 18, but then Person becomes the address of another memory space. And at the end, it returns the address of this other memory space, and assigns it to P2.

Object type

Object types differ from primitive types in that primitive types store values, whereas object types store addresses (Pointers).

When you create an object type, the computer creates a space in memory for us to store the value, but we need to find the space, which will have an address (pointer).

Correct determination of NULL

console.log(typeof null); //object
Object.prototype.toString.call(null) // "[object Null]" 
Copy the code

typeof vs instanceof

Typeof displays the correct type for primitive types except null

typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol(a)// 'symbol'
Copy the code

For objects, all but functions display object, so TypeOF does not determine exactly what type a variable is.

typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
Copy the code

If we want to determine the correct type of an object, this is a good time to use Instanceof, because the internal mechanism is determined by the prototype chain.

const Person = function() {}
const p1 = new Person()
p1 instanceof Person // true

var str = 'hello world'
str instanceof String // false

var str1 = new String('hello world')
str1 instanceof String // true
Copy the code

For primitive types, you don’t want instanceof to determine the type directly, but there are ways to let Instanceof determine the primitive type

class PrimitiveString {
  static [Symbol.hasInstance](x) {
    return typeof x === 'string'}}console.log('hello world' instanceof PrimitiveString) // true
Copy the code

Type conversion

There are only three types of conversions in JS

  • Converts to a Boolean value
  • Convert to numbers
  • Convert to string

Turns a Boolean

All values except undefined, null, false, NaN, “”, 0, -0 are converted to true for conditional judgments, including all objects.

Object to primitive type

ValueOf is called first when a non-base type is converted, and toString is called if valueOf cannot return a valueOf the base type

The built-in [[ToPrimitive]] function is called when the object is converted. For this function, the algorithm logic is generally as follows:

  • First check whether the object existsvalueOfMethod, if it has and returns the original type, that value is used for casting;
  • ifvalueOfIf no primitive type is returned, usetoStringMethod return value;
  • ifvauleOftoStringIf neither method returns a primitive type value, one is emittedTypeErrorThe error.

It is also possible to override symbol.toprimitive, which has the highest priority when converted to a primitive type.

let a = {
  valueOf() {
    return 0
  },
  toString() {
    return '1'},Symbol.toPrimitive]() {
    return 2}}1 + a / / = > 3
Copy the code

Four operators

The addition operator differs from the other operators in that it has the following characteristics:

  • If one side of the operation is a string, the other side is also converted to a string.
  • If one party is not a string or number, it is converted to a number or string
1 + '1' / / '11'
true + true / / 2
4 + [1.2.3] 41, 2, 3 "/ /"
Copy the code

For operators other than addition, as long as one side is a number, the other side is converted to a number

4 * '3' / / 12
4 * [] / / 0
4 * [1.2] // NaN
Copy the code

Comparison operator

  • If it’s an object, it passestoPrimitiveConverting objects
  • If it is a string, it passesunicodeCharacter index to compare
let a = {
  valueOf() {
    return 0
  },
  toString() {
    return '1'
  }
}
a > -1 // true
Copy the code

== VS ===

For ==, if the types of the contrasting parties are different, a cast is performed.

If we need to compare whether X and y are the same, the following judgment process will be performed:

  1. The first step is to determine whether the two types are the same. If it’s the same, it’s the ratio
  2. If the type is not the same, then the type conversion is performed
  3. It decides if it’s a comparisonnullundefinedIf yes, it will returntrue
  4. Check whether the two types arestringnumberIf yes, the string is converted tonumber
  5. Determine if either party isbooleanIf it were, it wouldbooleantonumberRejudge
  6. Determine if either party isobjectAnd the other party isstring,numberorsymbolIf it were, it wouldobjectCast to the original type and judge

In the case of ===, it is to determine whether they are of the same type and value

[] = =! [] why true?

First look at the right,! The symbol will force the following variable to Boolean, and since [] is true to Boolean, the right-hand side will be false, and then according to rule 5 above, false will be converted to the number 0.

Then, on the left, if the sixth condition is met, valueOf is called, and since the empty array call valueOf is converted to 0, it returns true.

common

0.1 + 0.2 === 0.3? Why is that?

When the two numbers are added, the mantissa will be converted to binary first. When 0.1 and 0.2 are converted to binary, the mantissa will have an infinite loop, and then the order calculation will be carried out. JS engine truncates binary, resulting in loss of accuracy.

So to sum up: precision loss may occur in base conversion and logarithmic operation

How is the JS integer represented?

In accordance with IEEE754 standard, a Number is represented by 64 bits, (1 + 11 + 52) (1 digit character + 11 rank code + 52 mantis), the maximum security Number is math.pow (2, 53) -1. (sign bit + exponent bit + decimal significant bit)

symbolWhat’s the use

Can be used to represent a unique variable to prevent naming conflicts.

Can take advantage of the symbol will not be regular method (in addition to the Object. GetOwnPropertySymbols) traversal, so can be used to simulate the private variables.

Mainly used to provide traversal interface, layout of symbol. Iterator objects can use for···of loop, can be unified processing data structure. After the call, a traverser object is returned, which contains a next method. After the next method is used, two return values, value and done, indicate the current execution position of the function and whether the traversal is complete.

Symbol.for() provides global access to symbols.

{} + [] and [] + {}

[] + {} // "[object Object]"
{} + [] / / 0
Copy the code

Look at the first one, [] will be strongly converted to “”, {} will be strongly converted to the string “[object object]”. Add the two strings to get the final result.

Second, the compiler will treat {} as an empty block of code, which can be interpreted as a useless {} symbol in the global scope. {} + [] can be treated as + [], And + is forced to convert [] [] for the number, the process of transformation is + [] — > + “” – > 0 the end result is 0.

But we execute console.log({}+[]) and console.log([]+{}), and the result is the same, because {} doesn’t have a statement or expression header.

Symbol type conversion

  • Cannot be converted to a number
  • Can be converted to a Boolean value (both true)
  • Can be converted to the string “Symbol(cool)”

False value list

  • undefined
  • null
  • false
  • +0, -0, NaN
  • “”

NAN and Typeof NAN

Typeof NaN = ‘Number’ typeof NaN = ‘Number’

In js= =and= = =The difference between

A simple summary

In simple terms: == equals the same, === equals strictly the same, why do you say that,

If the two operand types are the same, compare them with ===; if they are different, compare them with ===; if the operand types are different, compare them with false.

Operand 1 == operand 2, operand 1 === operand 2

Comparison process:

Double equals == :

(1) If two values are of the same type, compare three equal signs (===) (2) If two values are of different types, they may be equal, so they need to be converted according to the following rules for comparison: a) If one value isnull, one isundefinedB) If one is a string and one is a number, convert the string to a number and then compareCopy the code

3 = = = = :

(1) If the types are different, they must not be equal (2) If both are numeric and have the same value, they are equal; If at least one of them isNaN, so it's not equal. (Check whether a value isNaN, can only be usedisNaNTo judge (from)3) If both are strings with the same characters in each position, they are equal, otherwise they are not. (4) if both values are truetrue, orfalse, then equal (5If both values refer to the same object or function, they are equal, otherwise they are not (6) if both values are truenull, orundefinedSo it's equal to.Copy the code

Determine the data type

In this article, we will look at the following four ways to determine JavaScript data types:

  • typeof()
  • instanceof()
  • constructor
  • Object.prototype.toString.call()

Whether it’s in an interview or at work, there’s a scenario that goes like this:

  • How do I determine the data type of a JavaScript field?

Of course, it may also be a bonus to a knowledge point, for example:

  • When you make a deep copy of data, how do you determine what type the field is? Do you know how many ways to determine data types? What are their advantages and disadvantages?

So, this article explains four ways to determine JavaScript data types!

Three typeof

/ * * *@name Typeof example *@description The return */ of each data type is detected through Typeof
const test = {
  testUndefined: undefined.testNull: null.testBoolean: true.testNumber: 123.testBigInt: BigInt(1234), // Greater than 2 to the 53rd power is BigInt
  testString: '123'.testSymbol: Symbol(),
  testFunction: function() {
    console.log('function');
  },
  testObject: {
    obj: 'yes',},testObjectString: new String('String'),
  testObjectNumber: new Number(123),}console.log(typeof(test.testUndefined)); // undefined
console.log(typeof(test.testNull));      // object
console.log(typeof(test.testBoolean));   // boolean
console.log(typeof(test.testNumber));    // number
console.log(typeof(test.testBigInt));    // bigint
console.log(typeof(test.testString));    // string
console.log(typeof(test.testSymbol));    // symbol
console.log(typeof(test.testFunction));  // function
console.log(typeof(test.testObject));    // object
console.log(typeof(test.testObjectString));    // object
console.log(typeof(test.testObjectNumber));    // object
Copy the code

As can be seen above, typeof allows us to determine most types, but it has drawbacks:

  1. judgetypeof null, you getobject;
  2. Judgment constructortypeof new String('String')ortypeof new Number(123)Such as… And you’ll getobject.

That is, there are some problems in determining data types through Typeof.

Four instanceof

/ * * *@name Instanceof Example 1 *@description Check the string type */
const simpleString = 'This is a simple String.';
const newString = new String('Here's the String that comes out of New.');

console.log(simpleString instanceof String); // false, check the prototype chain will return undefined
console.log(newString instanceof String); // true

/ * * *@name Instanceof Example 2 *@description Check the number type */
const simpleNumber = 123;
const newNumber = new Number(123);

console.log(simpleNumber instanceof Number); // false
console.log(newNumber instanceof Number); // true

/ * * *@name Instanceof Example 3 *@description Object type */
const simpleOjbect = {};
const newObject = new Object(a);console.log(simpleOjbect instanceof Object); // true
console.log(newObject instanceof Object); // true
Copy the code

As mentioned above, instanceof may not perform well, although it can detect data types, but ” instanceof String, 123 instanceof Number, etc. Return false, which does not satisfy our needs.

Instanceof is used to check whether the constructor’s prototype property is present in the prototype chain of an instance object. (Something to look forward to)

Five constructor

/ * * *@name The constructor example *@description Constructor detects the object type */
const arr = [];
console.log(arr.constructor === Array); // true

const obj = {};
console.log(obj.constructor === Object); // true

const num = 1;
console.log(num.constructor === Number); // true

const str = '1';
console.log(str.constructor === String); // true

const bool = true;
console.log(bool.constructor === Boolean); // true

const nul = null;
// console.log(nul.constructor); Uncaught TypeError: Cannot read property 'constructor' of null at 
      
       :1:5
      

const undefin = undefined;
// console.log(undefin.constructor); Uncaught TypeError: Cannot read property 'constructor' of null at 
      
       :1:5
      
Copy the code

Unlike typeof and instanceof, which belong to the class of expressions and operators, constructor is directly related to the built-in Object.

[].constructor === Array or (1).constructor === Number returns true, as expected.

Constructor (); / / Uncaught TypeError (); / / Uncaught TypeError: Cannot read property ‘constructor’ of null at

:1:5

Six Object. ToString. Call ()

Object.prototype.toString.call()

/ * * *@name The toString example *@description ToString Checks the object type */
const toString = Object.prototype.toString;

console.log(toString.call(new Date));     // [object Date]
console.log(toString.call(new String));   // [object String]
console.log(toString.call(Math));         // [object Math]
console.log(toString.call('feHuang'));    // [object String]
console.log(toString.call(123));          // [object Number]
console.log(toString.call([]));           // [object Array]
console.log(toString.call({}));           // [object Object]
console.log(toString.call(undefined));    // [object Undefined]
console.log(toString.call(null));         // [object Null]
Copy the code

In the previous three under the condition of the heart is unable to do, Object. The prototype. ToString. Call () is stable and practical.

If you look at the jQuery source code, you will see that its datatype detection is also implemented through this method (jquery.type (obj)).

In terms of detecting data types, You regardless of the test Object. The prototype. ToString. Call (” aaa “) and the Object. The prototype. The toString. Call or (null) Object. The prototype. ToString. Call (undefined) can get what you want the type of format: [Object String], [Object Null], [Object undefined].

Seven summarizes

Above, through comparison, we come to the conclusion that it is recommended to use:

  • Object.prototype.toString.call()

Of course, even though our article may seem short and concise, we have covered the advantages and disadvantages of these four methods for determining data types.

At the same time

  • apply()
  • bind()
  • call()
  • The difference between apply(), bind() and call()

Back to the top write

The principle of the Object. The prototype. The toString method

In JavaScript, Object to determine whether a value belongs to the kind of built-in types, the most of it is through the Object. The prototype. The toString method.

var arr = [];
console.log(Object.prototype.toString.call(arr))  //"[object Array]"
Copy the code

This article is about how and how the toString method does this.

ECMAScript 3

In ES3, Object. The prototype. The toString method specification is as follows:

  • 15.2.4.2 Object. The prototype. The toString ()

    When the **toString method is called, the following steps are performed :1. Return the value of the [[Class]] attribute of this object. Returns Result(2) of the second step.

[[Class]] is an internal property that all objects (native and host) have. In the specification,[[Class]] is defined this way

Internal properties describe
[[Class]] A string value indicating the type of the object.

Then he gave an explanation:

The value of the [[Class]] property of all built-in objects is defined by this specification. The value of the [[Class]] property of all host objects can be any value, even the value of the [[Class]] property used by the built-in object. The value of the [[Class]] property can be used to determine which built-in type a native object belongs to. It is important to note that in addition to * * Object. The prototype. The toString method of * *, this specification does not provide any other way to access the value of the attribute (see 15.2.4.2).

In other words, the Object. The prototype. The toString () method returns the string, remove the front fixed * * [Object. $.type(); $.type(); $.type(); $.type();

In ES3, the specification does not specify the number of internal attributes of [[class]], but we can count the total number of internal attributes of [[class]] for native objects. Respectively is: “Array”, “Boolean”, “Date”, “Error”, “Function” ` ` `, “Math”, “Number”, “Object”, “the RegExp”, “String”. `

ECMAScript 5

In ES5.1, except some written specification more detailed Object. The prototype. The toString method and [[class]] internal attributes, there are some changes in the definition of the Object. The prototype. The toString method specification is as follows:

15.2.4.2 Object. The prototype. The toString ()

When the **toString** method is called, the following steps are performed:

  1. ifthisThe value ofundefined, the return"[object Undefined]".
  2. ifthisThe value ofnull, the return"[object Null]".
  3. letOBecomes the result of calling ToObject(**this)**.
  4. letclassBecome aOThe value of the internal attribute [[Class]] of
  5. Returns three strings **"[object ",天安门事件class, as well as"]"New string after concatenation.

As you can see, there are 1,2,3 more steps than ES3. The first and second rules are new and special because “Undefined” and “Null” do not belong to the [[class]] attribute. Note that this does not apply to strict mode (most functions will keep Undefined or Null in strict mode, and will automatically become full in non-strict mode) Bureau of objects). Step 3 is not a new rule, because in the ES3 engine, the three primitive value types are converted to the corresponding wrapper objects in this step, but it is not written in the specification. In ES5, the [[Class]] attribute is explained in more detail:

The value of the [[Class]] property of all built-in objects is defined by this specification. All host object [[Class]] property values can be in addition to “Arguments”, “Array”, “Boolean”, “Date”, “Error”, “Function”, “JSON”, “Math”, “Number”, Any String other than “Object”, “RegExp”, or “String”.[[Class]] Internal attributes are used internally by the engine to determine what type of value an Object belongs to. It is important to note that in addition to * * Object. The prototype. The toString method of * *, this specification does not provide any other way to access the value of the attribute (see 15.2.4.2).

Arguments Object [[class]] has become “arguments” instead of “Object”, and JSON has multiple global objects ([[class]]) with its [[class] ]] value for “JSON”. The second difference is that the values of the [[class]] internal attributes of the host object cannot conflict with these 12 values, although es3-enabled browsers do not seem to find any host objects that intentionally use these 10 values.

ECMAScript 6

ES6 is currently only a working draft, but it is certain that the [[class]] internal attribute is removed and replaced by another internal attribute [[NativeBrand]]. The [[NativeBrand]] attribute is defined as follows:

Internal properties Attribute values describe
[[NativeBrand]] Enumerates a member of NativeBrand. The value of this attribute corresponds to a tag value that can be used to distinguish the type of the native object.

[[NativeBrand]]

The [[NativeBrand]] internal attribute is used to identify whether a native object is a particular type of object that complies with this specification. The value of the [[NativeBrand]] internal attribute is one of the following enumerated types :NativeFunction, NativeArray, StringWrapper, BooleanWrapper, NumberWrapper, NativeMath, NativeDate, NativeRegExp, NativeError, NativeJSON, NativeArguments, NativePrivateName.[[NativeBrand]] Internal attributes are only used to distinguish between ECMAScript native objects of a particular type. Only the object types specified in Table 10 have [[NativeBrand]] internal attributes.

Table 10 — Values of [[NativeBrand]] internal attributes

Attribute values Corresponding to the type
NativeFunction Function objects
NativeArray Array objects
StringWrapper String objects
BooleanWrapper Boolean objects
NumberWrapper Number objects
NativeMath The Math object
NativeDate Date objects
NativeRegExp RegExp objects
NativeError Error objects
NativeJSON The JSON object
NativeArguments Arguments objects
NativePrivateName Private Name objects

Unlike [[class]], not every object has [[NativeBrand]]. At the same time, the Object. The prototype. ToString method specification is changed to the following:

15.2.4.2 Object. The prototype. The toString ()

When the **toString** method is called, the following steps are performed:

  1. ifthisThe value ofundefined, the return"[object Undefined]".
  2. If ` `thisThe value ofnull, the return"[object Null]".
  3. letOBecomes the result of calling ToObject(**this)**.
  4. ifOThere are [[NativeBrand]] internal attributes that lettagBecomes the corresponding value in Table 29.
  5. Otherwise,
    1. lethasTagBe invokedOThe result of the [[HasProperty]] internal method of the.
    2. ifhasTagforfalse, then lettagfor"Object".
    3. Otherwise,
      1. lettagBe invokedOIs the result of the [[Get]] internal method of the @@toStringTag.
      2. iftagIs an abrupt completiontagBe NormalCompletion ("?????").
      3. lettagBecome atag.[[value]].
      4. If Type (tag) is not a stringThe tag to become"?????".
      5. iftagThe value of"Arguments"."Array"."Boolean"."Date"."Error"."Function"."JSON"."Math"."Number"."Object"."RegExp".Or any of "String", then lettagBecome a string"~" andtagThe result of joining the current value.
  6. Return three strings “[object “, tag, and “]” ‘to concatenate the new string.

Table 29 — [[NativeBrand]] flag values

[[NativeBrand]] Flag values
NativeFunction "Function"
NativeArray "Array"
StringWrapper "String"
BooleanWrapper "Boolean"
NumberWrapper "Number"
NativeMath "Math"
NativeDate "Date"
NativeRegExp "RegExp"
NativeError "Error"
NativeJSON "JSON"
NativeArguments "Arguments"

As you can see, there is a big change in the specification, but to the average user, it doesn’t seem to be noticeable.

As you may have noticed, the new types in ES6, Map,Set, etc., are not in Table 29. What do they return when they execute the toString method?

console.log(Object.prototype.toString.call(Map()))   //"[object Map]"

console.log(Object.prototype.toString.call(Set()))   //"[object Set]"
Copy the code

Where does the string “Map” come from?

15.14.5.13 Map. Prototype. @ @ toStringTag

The @@toStringTag attribute starts with the string **”Map”**.

As the specification of ES6 is still under development, all relevant regulations are subject to change, so if you want to know more details. Looking at the following two links, all you need to know for now is that [[class]] is gone, using a more complex mechanism.

Stackoverflow.com/questions/1…

Mail.mozilla.org/pipermail/e…