Data type

1. What are the data types of JavaScript and their differences?

Javascript has eight data types: Number, String, undefined, NULL, Boolean, Symbol, BigInt, and Object.

Symbol and BigInt are new data types in ES6:

  • Symbol represents unique and immutable data types created to address potential global variable conflicts
  • BigInt is a type of numeric data. It can represent an integer in any precision format. BigInt can safely store and manipulate large integers, even if the Number exceeds the safe integer range that Number can represent.

These data can be divided into raw data types and reference data types:

  • Primitive data types: All types other than Object are immutable (the value itself cannot be changed)

  • Reference data types: object array functions, etc

The main difference between the two data types is where they are stored:

  • Primitive data types are simple segments of data stored directly on the stack that take up small space, are fixed in size, and are stored on the stack because they are frequently used
  • Reference data types are stored in the heap and occupy different sizes of space. Storing these data on the stack can affect program performance. The reference data type stores a pointer on the stack to the starting address of the entity in the heap. When used, it finds the address of the heap referenced in the stack and then retrieves the entity in the heap from the address

The concepts of heap and stack exist in data structures and operating system memory

Data structure:

Stack: Data is accessed in a fifo mode

Heap: Priority queue, sorted by priority, which can be specified by size

Operating system:

Stack: The memory in the stack area is automatically allocated and released by the compiler to store function parameter values, local variable values, etc. Operation mode is also first in last out

Heap: Memory in the heap is usually allocated and freed by the developer. If the developer does not free it, it may be reclaimed by the garbage collection mechanism at the end of the program.

Note: The interview can be divided into five points, which are described one by one. First, what are the basic data types? Then, what are the differences between the basic data types and reference data types

2. How to detect data types?

Typeof:

Variables and nulls of reference types are judged to be Object, and everything else is fine

InstanceOf:

Can be used to determine the type of the object, not the basic type of data. The idea is to use a prototype chain

The constructor:

Constructor serves both the purpose of determining the type of data and that the instance object accesses its constructor. Note that if we change the prototype of a function object, its instance object cannot use constructor to determine the type.

Object.prototype.toString.call()

Use the toString method on the Object prototype to determine the data type

3. What are the ways to determine arrays?

  • Object.prototype.toString.call()
  • Array. IsArray (obj) method
  • instanceOf
  • Array. The prototype. IsPrototypeOf (obj) : on the prototype chain of obj search Array

4. Null and undefined

First of all, they are all basic data types in JavaScript, and the values of both types are unique to themselves.

And then the main difference:

  • Undefined means that the current variable has no assigned value. Null is when we manually assign a null to the current variable, and it usually represents an empty object (and is often charged when the variable is no longer in use, so that the browser can reclaim the previous garbage object reference).
  • Typeof returns a different typeof value, undefined returns undefined and null returns an Object

Keyword: undefined, empty object

5. Why does null return an Object

There are different explanations for this problem, some say it’s a bug, some say it’s design.

I think:

Null is an empty object by definition.

From a logical point of view, a null value represents an empty object pointer, which is why “object” is returned when the Typeof operator is used to detect null values.

Deeper understanding:

In the first version of JavaScript, all values are stored in 32-bit cells, each containing a small type label (1-3bits) and the real data we want to actually store the value in. Type labels are stored in the lower level of each unit.

000: object - The data currently stored points to an object. 1: int - The data currently stored is a 31-bit signed integer. 010: double - The data currently stored points to a double floating-point number. 100: String - The data currently stored points to a string. 110: Boolean - The data currently stored is Boolean.Copy the code

If the least significant is 1, the length of the type label flag bit is only one bit. If the least significant is 0, the type label flag bit is three digits long.

There are two special types:

  • The value of undefined is (-2) to the 30th
  • The value of null is the machine code null pointer.

That is, the type label of null is the same as the type label of object, so it will be identified as object.

Key word: type label, null and Object type label is 000.

In the earliest days of JavaScript, values were stored in 32-bit units, each containing a type tag that was used to determine the type of the data. However, type labels of type NULL and Object are designed to be equal. So NULL is of type Object

6. Implementation principle and implementation of intanceof operator

A instance B

First, let’s be clear about what instance does: Return true if B’s explicit prototype object is on A’s prototype chain

Interviewer: Write an instanceof by hand, young man!

Ok!

  function instancof(left, right) {
    let leftp = left.__proto__;// Get the left implicit prototype
    let rightp = right.prototype;// Get a reference to right's explicit prototype object
    // The search is over
    while (true) {
      if (leftp == null) {
        false
      }
      if (leftp == rightp) {
        return true
      }
      leftp = leftp.__proto__
    }
  }
Copy the code

Writing an instance by hand is not difficult. Here are some questions to stimulate you:

  console.log(Object instanceof Function)//true
  console.log(Object instanceof Object)//true
  console.log(Function instanceof Function)//true
  console.log(Function instanceof Object)//true
  function Foo(params) {}console.log(Object instanceof Foo);//false
Copy the code

Remember that the principle of instance is to determine whether the prototype of a function object is in the prototype chain of the previous example object, so we can easily write the principle and the result.

7. Why 0.1+0.2! == 0.3, how do I make it equal?

Key words: precision loss

This is the flow of the browser’s calculation:

First, the computer will first convert the data into binary numbers, and then perform subsequent operations. However, in modern browsers, binary numbers are stored as floating-point numbers, so it is necessary to convert binary numbers to floating-point numbers. Finally, the resulting binary floating point numbers are added. Convert a floating point number to a decimal number after the calculation.

Note: Floating point numbers are classified as single-precision floating point numbers for 32-bit operating systems and double-precision floating point numbers for 64-bit operating systems.

The answer to this question:

Two precision losses occurred in the calculation.

First loss of precision: when converting binary 0.1 and 0.2 into floating point numbers, the binary floating point number can only store 52 decimal places, resulting in the operation of 1 to 0, which will cause the loss of precision.

Second precision loss: when the binary floating-point numbers are added, the number of decimal places is added, and the number of 53 digits is rounded off by 1 or 0

Possible bugs:

Price 300.01, discount 300 yuan appear payment amount less than 0.01 yuan (the minimum face value of RMB is 0.01 yuan), etc

Solution:

You can use math.tofixed () or number.epsion in ES6

8. How to get a safe undefined value

Undefined is a Z identifier, so it can be taken as the value of a variable, but doing so will affect the normal judgment of undefined. The expression void returns no value, so the result returns undefined. So we can use void 0 to get a safe undefined value.

9. What is the result of typeof NaN

First, NaN means “a value that is not a number,” which is usually returned when an error occurs in our calculation.

Typeof NaN values are Number

NaN is a special value that is unique and not equal to itself, that is, NaN=== the result of NaN is false

10. IsNaN and Number. IsNaN functions

IsNaN (): This function first attempts to convert the incoming data to a number. If it cannot convert, it returns true, so that String and Boolean data will return true

Number.isnan (): This method is new in ES6. It first checks whether the internal Number is a Number and does not perform type conversion. Therefore, it is more specific to compare only numbers with NaN, and return false if anything else

11. Cast rules for the == operator

For ==, if the two types are different, the type conversion will be performed as follows:

  1. If both parties have the same data type, compare the content directly
  2. Return true if you are comparing null and undefined
  3. If it’s Number and String, convert String to Number
  4. If Boolean and Number, convert Boolean to Number
  5. If one side has Object and one side is string, number, or symbol, convert Object to the primitive type

12. Go to the string rule for other values

  • Null and Undefined convert directly
  • Boolean direct conversion
  • The Number type is converted directly, and extremely small numbers are converted to exponents
  • Values of type symbol are converted directly, but only casts are allowed to display. Implicit conversions report errors
  • An ordinary Object that does not have its own toString() method calls Object’s toString() method, which returns “[Object Object]”.

13. Other values go to the numerical value rule

  • The undefined type is converted to NaN
  • The null type is converted to 0
  • Boolean values are 0,1
  • The String type is converted to a number if it contains a number, to NaN if it is non-number, and to 0 if it is empty
  • Values of type Symbol cannot be converted to numbers and an error is reported
  • Values of object types are first converted to values of primitive types and then converted according to the above rules

14. Other values go to the Boolean value rule

These are false values:

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

Everything else is true

15. | | and && operator return values

| | and && first conditions can be carried to the first operand

  • | | when the first value is true then returns true, if false is returned to the second operand
  • && returns the second operand if the first value is true, or false if false

They all return the result of one of the operands, not the result of a conditional judgment

16.Object.is() differs from the comparison operators “===” and “==”

  • “==” in the judgment of equality, if the types of the two sides are inconsistent, the comparison will be performed after implicit type conversion
  • “===” if the two types are not the same, return false
  • Object.is() is more or less like the equal sign, except that it does things like NaN is equal to NaN, and “+0” and “-0” don’t want to be equal
  console.log(Object.is(NaN,NaN))//true
Copy the code

17. What is a wrapper type in JavaScript

In JavaScript, primitive types have no properties or methods, but to facilitate manipulation of primitive type values, JavaScript implicitly converts primitive type values to objects when calling primitive type properties and methods

Such as:

let a='12';
console.log(a.length)
Copy the code

As we access some properties, Javascript converts the String ’12’ into a String(‘ ABC ‘) in the background, and then accesses the corresponding property.

Javascript can also explicitly convert a primitive type to a wrapper type through Object, and then convert the wrapper type to a primitive type through the valueOf method. It is also often used for explicit type conversions

18. How do implicit conversions work in JavaScript

In JS, when the data types on both sides of the operator are not uniform, the operation cannot be carried out. At this time, the JS engine will implicitly convert the data types on both sides of the operator to the same type and then perform the operation.

The three main conversion modes involved are:

  1. Convert a reference type value to the original value: ToPrimitive()
  2. Convert values to numbers, ToNumber()
  3. Convert the value to a string, ToString()

Here’s how the ToPrimitive() function executes: JavaScript typically uses this parameter to convert every value ToPrimitive data, so it’s often used in reference types. It’s going to look something like this.

ToPrimitive(obj,type)
Copy the code

It takes two arguments, obj is the object itself, and type is the type of result we expect, usually String and Number.

If type is number, the rule is as follows:

  • Call the valueOf method of obj, returning if a raw value is returned, otherwise go to the next step
  • Call obj’s toString method, as above
  • Raises a TypeError exception

If type is string, the rule is as follows:

  • Call obj’s toString method, returning if a raw value is returned, otherwise go to the next step
  • Call the valueOf method of obj, as above
  • Raises a TypeError exception

The main difference is the type parameter. The default value of the type parameter is number, but the value of the Date object is string.

Here are the rules for implicitly converting values of primitive types to different operators:

  1. The + operator: **(string and number)** If there is at least one string variable on both sides, the variables on both sides are implicitly converted to strings. Otherwise, the variables on both sides are converted to numbers.
1 + '23' / / '123'
 1 + false / / 1
 1 + Symbol(a)// Uncaught TypeError: Cannot convert a Symbol value to a number
 '1' + false // '1false'
 false + true / / 1
Copy the code
  1. The -, *, /, % operators: **(number)** Can only be used for the number type. Other types are converted to number
1 * '23' / / 23
 1 * false / / 0
 1 / 'aa' // NaN
Copy the code
  1. The = = operator:(number)

3= =true // false,true converts number to 1
'0'= =false //true, '0' converts to number 0, false converts to number 0
'0'= =0 // '0' converts to number 0
Copy the code
  1. for<and>Comparison operators

If both sides are strings, the alphabetical order is compared

'ca' < 'bd' // false
'a' < 'b' // true
Copy the code

In other cases, converting to numbers and then comparing, including objects, is converted to primitive types

'12' < 13 // true
false > -1 // true
Copy the code

For example, the output and internal execution of this line of code:

var a = {}
a > 2 // false
a >'a' //false
Copy the code

ValueOf () returns {}. ToString () returns [object object]. The first line of code outputs false, and the second line of code returns false by comparing the first string

19.+When is the operator used to concatenate strings

The + operator concatenates strings as long as the data on either side is a string or can be converted to a string in some way, such as by the toPrimitive() function. Otherwise do the math

There are exceptions, such as:

2+{} // output "2[object object]"Copy the code

This is because when {} comes first, browsers automatically think of it as a block-level scope, so they go straight to the next step. Different browsers have different results. So the second one was the answer I was looking for.

20. Why BigInt proposal

JavaScript introduces the Bigint proposal because it can lose accuracy if the number is computed beyond the specified maximum safe number.

2. JavaScript basis

1. What are the methods and usage scenarios for JS to access internal data variables?

There are two main ways to read and set object properties:

(.). Method: obj. Attr ([]) method: obj[attr]

Grammar is the way we usually use it.

[] is usually used in the following scenarios:

  • The attribute name contains special characters such as – space
  • Variable name indeterminate ([] can be a variable, or a string)

Usage:

let p={}
  let address='address'
  p.name='name'
  p['age'] =12
  p[address]='quiet'
  console.log(p)
Copy the code

2. What are the four ways that Javascript functions can be called?

  • Call the function directly (through the window)
  • Call by object
  • New call (calling a function using a constructor)
  • Call through bind/call/apply

3. Implementation principle of the new operator

To understand how the new operator works, you need to understand what new does. As we all know, we use the new operator when we instantiate our constructors as objects.

To really master and write a new, you need to know about prototypes and prototype chains and the this binding.

In fact, the internal process of New is very simple, which is basically the following steps:

  1. Create a new object, obj
  2. Points the implicit stereotype of an object to the stereotype object of the constructor
  3. Call the constructor with apply (change this to obj)
  4. Return obj, if the constructor has a value, reference object if the value is a reference type, and obj if it is primitive

Writing:

  function MyNew() {
    // Get the list of parameters, get the constructor and its parameters
    let [ArgFun, ...arg] = [...arguments]
    // Define an empty object
    let obj = {};
    // Prototype pointing
    obj.__proto__ = ArgFun.prototype;
    // Set this to point
    let tartgetObj = ArgFun.apply(obj, arg)
    // Call the constructor with apply (change this to obj)
    return tartgetObj instanceof Object= =true ? tartgetObj : obj
  }
Copy the code

Use:

  function Person(name, age) {
    this.name = name;
    this.age = age;
    console.log('execution')
    return '12'
  }

  let zhangsan = MyNew(Person, 'Joe'.12)
  console.log(zhangsan)

Copy the code

4. What native methods do arrays have

  1. Pop () and push() tail operations, delete and add
  2. Shift () and unshift() headers, delete and add
  3. Sort (), a function that takes two arguments and returns an array by subtracting two arguments
  4. Reserve () reverses an array, which also returns an array, changing it
  5. Concat (), concatenates two arrays, returns the concatenated array without changing the original array
  6. Slice (), which takes a portion of an array and returns it, without affecting the original array
  7. Splice (), which can delete, replace, or insert one or more elements of an array, return the array, and alter the original array
  8. The filter() function returns the filtered array without changing the original array
  9. The map() function iterates through the array without changing the original array
  10. Reduce (), a summary, can operate on each array element. The parameters are a function and a default value. The function has two parameters, respectively representing the result of the last calculation and the current value.

5. What are DOM and BOM

Answer this question by including ECMAScript as well.

JavaScript is made up of three parts: ECMAScript, DOM, and BOM. Their functions and tasks are also different:

ECMAScript: Specifies language basics such as syntax, keywords, operators, etc. It specifies language standards such as ES5, ES6, etc

DOM: Document object model that provides methods and interfaces for accessing and manipulating web page content. DOM maps the entire page into a structure of multi-level nodes, each of which is treated as an object, resulting in a DOM tree. If we want to get the object of a node, we just need to get the object layer by layer and then operate it.

BOM: Browser object model that provides methods and interfaces to and from the browser. At the heart of the BOM is the Window object. Windows also provides apis for manipulating the browser, such as the History property, navigator, and Location objects.

Note: Window has a dual identity. It is not only an interface for JS to operate the browser window, but also a global object, which can operate any variable object in the web page

6. The understanding of class array (pseudo-array), how to convert to array

Class array is a pseudo-array, is a kind of array-like object, has the length attribute and a number of index attributes of the object, but can not call the array method

Common array-like objects are arguments and the result returned by DOM methods.

Common ways to convert an array of classes to an array are as follows:

1. Call the array’s slice method via call:

Array.prototype.slice.call(arrayLike);
Copy the code

2. Call the array’s splice method via call:

Array.prototype.splice.call(arrayLike, 0);
Copy the code

3. Call concat methods such as arrays through call

Array.prototype.splice.call(arrayLike, 0)
Copy the code

4. Use the array. from method to convert

Array.from(arrayLike);
Copy the code

5. You can also use the ES6 extension operator

7. Why tail calls?

A first call is simply a call to another function at the end of its execution. We know that function execution is stack based, so the last step of our current function is off the stack, and then we call another function. The advantage of this is that we don’t have to keep the stack of the current function, thus saving memory. This is called tail-call optimization

8.for… In and for… The difference of

  1. For in gets the key name of the object, and for of gets the key of the object
  2. For in traverses the prototype chain of an object and is not recommended for poor performance, while for of traverses only the current object and does not traverse the prototype chain
  3. For in returns all enumerable properties of the array, and for of returns the values of the array line markers.

Summary: For in is mainly used to iterate over objects, not groups of numbers. For of loops can iterate over objects, arrays, array-like objects, etc.

9. Ajax understanding to implement an Ajax request

This is the asynchronous communication of JavaScript, the technique of requesting data asynchronously, getting json data from the server, and updating it to the entire page without refreshing the entire page. This is the biggest advantage of Ajax.

At the heart of Ajax is the XmlHttpRequest object, which JavaScript can use to make requests and process responses without blocking the user.

** HOW it works: ** I think of Ajax as an intermediate layer between the browser and the server, where the client sends a request, the request goes to the XHR object, the XHR sends the request to the server, the server does the business, the server sends the response data to XHR, and JavaScript writes the page.

Steps to create an Ajax request:

  1. Create an XmlHttpRequest object
  2. Create an Http request (you can set the request mode, address, and asynchrony)
  3. Add information and listener functions (such as adding request headers and listening for XHR status)
  4. Send the request (parameters can be passed when post)

We use the following callback to encapsulate a network request function:

  function getData(url, hander) {
    let xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onreadystatechange = function () {
      if (this.readyState ! = =4) return
      if (this.status == 200) {
        hander(this.response)
      } else {
        console.error(this.statusText)
      }
    }
    xhr.onerror = function () {
      console.log(this.statusText)
    }
    xhr.setRequestHeader("Accept"."application/json")
    xhr.send();
  }
Copy the code

Usage:

	getData('http://httpbin.org/get'.(data) = > {
    console.log(data)
  })
Copy the code

You can also use the promise wrapper:

function UseP(url) {
    return new Promise((resolve, reject) = > {
      let xhr = new XMLHttpRequest();
      xhr.open('GET', url, true);
      xhr.onreadystatechange = function () {
        if (this.readyState ! =4) return
        if (this.status == 200) {
          resolve(this.response)
        } else {
          reject(this.statusText)
        }
      }
      xhr.onerror = function () {
        reject(this.statusText)
      }
      xhr.responseType = 'json'
      xhr.setRequestHeader('Accept'.'application/json')
      xhr.send()
    })
  }
Copy the code

Use:

 UseP('http://httpbin.org/get').then((res) = > {
    console.log(res)
  }).catch((err) = > {
    console.log(err)
  })
Copy the code

10. Differences between Ajax, Axios, and FETCH

Ajax:

A technique for updating parts of a web page without having to reload them. A small amount of data is exchanged with the server through the background. Ajax enables asynchronous updating of web pages. Traditional web pages need to reload the entire page if they need to update the content.

Ajax has the following disadvantages:

  1. Itself is targeted at MVC programming, not in line with the tide of front-end MVVM
  2. Developed based on native XHR, the architecture of XHR itself is unclear
  3. Does not conform to the principle of separation of concerns
  4. Configuration and invocation are messy, and the event-based asynchronous model is unfriendly

Axios:

The HTTP client for the browser and NodeJS is essentially a wrapper around the native XHR, but it’s an implementation version of Promise. There are the following special provisions:

  1. Initiates an XMLHttpRequest request from the browser
  2. The Node sends an HTTP request
  3. Supporting Promise API
  4. Client support prevents CSRF
  5. Provides some interfaces for concurrent requests
  6. Intercept requests and responses
  7. Transform request and response data
  8. Cancel the request
  9. Automatically convert to JSON format

PS: To prevent CSRF: it is to make every request of you carry a key obtained from the cookie. According to the same origin policy of the browser, the fake website cannot get the key obtained from your cookie. In this way, the background can easily identify whether the request is a misleading input of the user on the fake website, so as to adopt the correct policy.

Fetch:

Alternatives to Ajax. Design based on Promise. Fetch’s code structure is much simpler than Ajax, and the parameters are a bit like jQuery Ajax. However, keep in mind that FETCH is not a further encapsulation of Ajax, but rather native JS that does not use XMLHttpRequest objects.

Advantages of Fetch:

  • Syntax concise, more semantic
  • Standards-based Promise implementation that supports async/await
  • More low-level, provide rich API
  • From the XHR

Disadvantages:

  • Error only for network requests, not for status codes returned by the server
  • Fetch (URL, {credentials: ‘include’})
  • Fetch does not support abort and timeout control. The timeout control implemented by setTimeout and Promise.reject cannot prevent the request process from continuing to run in the background, resulting in waste of traffic
  • Fetch has no way of natively monitoring the progress of requests, whereas XHR does

11. What are the methods of lazy loading of Javascript scripts?

Lazy loading means to load JavaScript files after the page is loaded. Lazy loading of JS helps to improve the speed of page loading

Generally, there are the following ways:

  1. The defer attribute: Add the defer attribute to the JS script. This allows the script to be loaded and the document to be parsed at the same time, and then execute the script file after the document is parsed, so that rendering of the page is not blocked. Several scripts that have the defer property set end up executing sequentially according to the spec, but this may not be the case in some browsers (keywords: synchronous, sequential)
  2. Async property: Add async property to the JS script. This property causes the loading of the script and the parsing of the document to be executed asynchronously. This property does not block the parsing of the page, but the execution of the JS script immediately after the script is loaded will also block if the document is not parsed. The order of scripts with multiple Async properties is unpredictable and generally does not follow the order of the code. (Keywords: asynchronous, may block, out of order)
  3. Dynamic CREATION of DOM: Dynamic creation of DOM tags, you can listen for the document loading event, after the document is loaded, you can dynamically create script tags to import JS scripts
  4. Use setTimeout delay: Set a timer to delay loading JS script files
  5. Loading JS files last: Place JS scripts at the bottom of the document so that JS scripts are loaded and executed as last as possible

12.CommonJS and ES6 module similarities and differences?

The difference between:

  • CommonJS is a shallow copy of the module, ES6module is a reference to the module; That is, ES6 cannot change the value of a pointer, which is equivalent to const
  • When the import interface is read-only, its variable value cannot be modified. That is, the address pointing of a variable cannot be changed, but the value inside the variable can be changed. You can reassign to CommonJS (change pointer pointer)

Thing in common:

Both CommonJS and ES6 Modules can assign values to imported objects, that is, change the values of the internal properties of the object

3. ES6

1. Let, var, const

There are several ways to answer this question:

1. Block-level scope: Let and const have block-level scope. Var has no concept of block-level scope. Block-level scopes solve two problems in ES5: that inner variables can override outer variables and that loops leak loop variables as global variables

2. Variable promotion: Var has variable promotion, let and const do not have variable promotion (can only be used after declaration), involving the concept of context

3. Add attributes to the global: Under a global window, var declares a global variable and adds it to the properties of the global object. Let and const do not.

Var can be repeated; let, const can’t

5. Temporary dead zones: Let and const variables are not available until they are declared, which of course applies to block-level scopes

ES6 explicitly states that if there are let and const commands in a block, the variables declared by the block to those commands form a closed scope from the start. Any time these variables are used before declaration, an error is reported.

6. Initialization: Let and var may not specify an initial value, but const must specify an initial value

7. Pointer pointing: Let variables can change pointer pointing, but const variables cannot change pointer pointing.

2. Can properties of const objects be modified?

What const guarantees is not that the value of a variable cannot be changed, but that the memory address to which the variable points cannot be changed. So for primitive types of data, the value is stored in the memory address that the variable points to, so it cannot be changed. Equivalent to a constant;

However, when our variable refers to an address of a reference type, our const can only guarantee that the address pointer to which it points cannot be changed, but we have no control over its memory contents.

3. What happens if you create a new arrow function?

Let’s start with the implementation steps of the new operator:

  1. Create a new object
  2. The constructor’s scope is then assigned to the new object (that is, to the object’s__proto__Property points to the constructor’s Prototype property.
  3. This in the constructor refers to the object and executes
  4. Return a new object

Looking back at the problem, the arrow function, introduced in ES6, has no prototype property of its own, no this to point to, and no argument. Therefore, it does not have the condition to new an instance object **, so an error will be reported if you simply new an arrow function. Error ** indicating that the arrow function is not a constructor

4. Difference between arrow function and ordinary function

1. Arrow functions are more concise than normal functions

2. Arrow functions do not have their own this

The arrow function’s this always points to the level above its current scope

var id = 'GLOBAL';
var obj = {
  id: 'OBJ'.b: () = > {
    console.log(this.id); }}; obj.b();// 'GLOBAL'
Copy the code

3. The this pointer inherited from the arrow function never changes

4. Call (), apply(), bind(), and other methods cannot change the this pointer in the arrow function

5. Arrow functions cannot be used as constructors

6. Arrow functions have no arguments of their own

7. Arrow functions have no prototype property

8. Arrow functions cannot be used as Generator functions and the yeild keyword cannot be used

5. Where does this point to in the arrow function?

The arrow function does not actually have its own this; its this actually inherits its this value from the parent of its scope. This is defined at the time of the definition and will not change.

You can use Babel to convert ES6 code into ES5 code to understand this:

ES6:

const obj = { getArrow() { return () => { console.log(this === obj); }; }}Copy the code

Babel:

// ES5, translated by Babel
var obj = { 
   getArrow: function getArrow() { 
     var _this = this; 
     return function () { 
        console.log(_this === obj); }; }};Copy the code

6. What are the functions and application scenarios of extended operators?

1. Extension operators for objects

The extension operator of an object is used to fetch all traversable properties of the object and copy them into the current object.

  let a = {name: 'a'.age: 12}
  letb = { ... a }Copy the code

Extension operators are equivalent to object.assign ()

 let a = {name: 'a'.age: 12}
 let b=Object.assign({},a)
Copy the code

The object.assign () method is used to merge methods, copying all the enumerable properties of the source Object to the target Object.

Its first argument is the target object, and the following arguments are the source object

For the application scenario of an object extension operator, the Reducer function must be a pure function in the Reducer of Redux, that is, we cannot directly operate the state state inside the function, so we can copy it directly using the extension operator to generate a new object and return it

Note: Both the extension operator and the object instance are shallow copies

2. Array extension operator

The array extension operator converts an array to a comma-separated sequence of arguments, expanding only one layer at a time.

Application Scenarios:

  • Converts an array to a sequence of parameters
  • Copy the array
  • Merge array
  • Used in combination with structure assignment to generate a new array.
  • Convert a string to an array **(algorithmic problem available)**
  • Converts the argument list argument to an array (insteadArray.prototype.slice.call(arguments))

7. Understand the structure of objects and arrays?

It’s just a way of fetching data from arrays and objects, where arrays are evaluated by position, and objects are evaluated by property name, regardless of position.

{deconstructed object :{next level object :{target attribute}}}

Such as:

const school = {
   classes: {
      stu: {
         name: 'Bob'.age: 24,}}}Copy the code

If we want to get name:

 let {classes: {stu:{name}}}=school
Copy the code

8. What do you understand about REST parameters?

The entire parameter of a function is an array. This is often used when the number of parameters of a function is uncertain.

function mutiple(. args) {
  console.log(args)
}
mutiple(1.2.3.4) // [1, 2, 3, 4]
Copy the code

10. Object. Assign and ES6 extension operators are deep copy or shallow copy, and what is the difference between them

Both are shallow copies.

Thing in common:

The common denominator is to take a copy of an old object and create a shallow copy of that object

Difference:

  • Object.assignThe function modifies its first tartget Object passed in, thus triggering the setter for ES6. If we use Proxy or Object.defineProperty to do anything else on the set method after modifying the set, we will encounter unexpected errors
  • And the extension operator gives us a normal JavaScript object, and it doesn’t really matter what we do, right

Prototype and prototype chain

1. Where does constructor point to on the prototype object

Each function has a Prototype property, which is a reference to the function’s prototype object. Each prototype object has a constructor property, which points to the function object itself.

Verify:

  function Fun(params) {}
  console.log(Fun.prototype.constructor==Fun)//true
  var a=new Fun();
  console.log(a.__proto__.constructor===Fun)//true
Copy the code

Explicit and implicit archetypes

First, we need to understand what the stereotype object does: it defines properties and methods shared by all object instances.

  • Each function has a prototype explicit property, which is just a reference to the prototype object

  • Each instance object has a __proto__, called an implicit prototype, which is also a reference. Eventually, it also points to the prototype object

The implicit prototype on the instance object has the same value as the prototype constructor corresponding to the instance; that is, the two different reference variable attributes point to the same block of address. All point to the prototype object

That is, in the chestnut below: the console outputs true

  function Fun(params) {}var a=new Fun();
  console.log(a.__proto__===Fun.prototype)
Copy the code

We can think of it as theta

  • This statement is executed on new:this.__proto__=Fun.prototype

It looks like this in memory:

3. Talk about prototypes and prototype chains

All the following concepts are my own understanding, if there is any mistake, please point out.

Prototype: Every function in JavaScript has a prototype property that holds a reference to an empty Object in memory. This Object is the function’s prototype Object and is used to share properties and variables. How to share? And that’s definitely using the concept of instance objects, where we instantiate this function, which in this case is also called a constructor, we instantiate multiple instance objects, so that all of our instances have access to properties or variables on our prototype object.

The first thing to know is two concepts: implicit prototype and __proto__. Implicit stereotypes are properties of instance objects, whereas explicit stereotypes are properties of functions. But the same thing is that they’re all a reference, and they don’t all point to the same block of memory, which is our prototype object.

Prototype Chains: Why are prototype chains called prototype chains? Simply because it is executed in a chained order of calls. In one sentence, it’s essentially looking for properties or methods along the implicit stereotype, so it’s also called the implicit stereotype chain. When we use an instance method to execute a property or method, we now assume that the desired property and method are in the prototype object. The order of execution in JavaScript memory is to look for the property or method in the prototype object via the __proto__ reference of the current instance. If the method does not have the property or method we are looking for, we continue in the __proto__ property of the current prototype Object into the memory referenced by __prote__, which is the prototype Object of the Object function (because we said earlier, The prototype property of each function refers to an empty Object instance, so there must be a __proto__ reference to the Object prototype. If it’s still not there, do some error handling. Because __proto__ is null in the prototype Object to which object. prototy points.

Next we can write some code to analyze its in-memory state:

function Fn() {
    this.test1=function(){
      console.log('test()')
    }
    Fn.prototype.test2=function(){
      console.log('test2()')}}let fn=new Fn();
  fn.test1();
  fn.test2();
  console.log(fn.toString())
  console.log(fn.test3)
Copy the code

The graph in memory looks something like this

  • fn.test1()The instance object has this method, so execute it directly
  • fn.test2(), first look in the sample object, find no, and then pass__proto__This property is found in the prototype object. perform
  • fn.toString(), according to the previous step, find the prototype object found does not have this property, then in__proto__To find, find, and execute a prototype object
  • fn.test3After finding the prototype Object of Object, and finding that there is still no Object, enter the implicit prototype of Object, where it has reached the end, soundefined

There are actually two things we can take note of:

  • **Object prototype objects are not Object sample objects: ** Display prototypes of functions default to point to instance objects of one Object at a time. One special exception, however, is the instance Object to which the Prototype property of Object itself points, because its implicit Prototype property points to NULL.
  • At the end of the prototype chain is the prototype Object of Object, because its implicit prototype is NULL

4. Relationship between Function, Object and prototype

Function is a relatively special Function because all functions are examples of Function, so the implicit prototype for each Function points to the prototype object of the Function.

The picture below is a very classic one. From the picture, we can see the following points:

  • All functions have two properties, explicit stereotypes (a sample Object pointing to Object) and implicit stereotypes (a prototype Object for Function).
  • Function is actually instantiating itself, so its implicit stereotype is executed, and therefore has its implicit stereotype equal to its explicit stereotype (this is a special case)
  • The Object Function is an example of Function, hence the Object in the figure.__Proto__Protype. In fact, we can see this result because all functions are Function examples, and Object is no exception

5. The prototype chain points to the topic

Now that you’ve seen this, why don’t you do some problems:

p.__proto__  // Person.prototype
Person.prototype.__proto__  // Object.prototype
p.__proto__.__proto__ //Object.prototype
p.__proto__.constructor.prototype.__proto__ // Object.prototype
Person.prototype.constructor.prototype.__proto__ // Object.prototype
p.__proto__.constructor // Person
Person.prototype.constructor  // Person
Copy the code

6. Explore instanceOf

A instance B

First, let’s be clear about what instance does: Return true if B’s explicit prototype object is on A’s prototype chain

Interviewer: Write an instanceof by hand, young man!

Ok!

  function instancof(left, right) {
    let leftp = left.__proto__;// Get the left implicit prototype
    let rightp = right.prototype;// Get a reference to right's explicit prototype object
    // The search is over
    while (true) {
      if (leftp == null) {
        false
      }
      if (leftp == rightp) {
        return
        true
      }
      leftp = leftp.__proto__
    }
  }
Copy the code

Writing an instance by hand is not difficult. Here are some questions to stimulate you:

  console.log(Object instanceof Function)//true
  console.log(Object instanceof Object)//true
  console.log(Function instanceof Function)//true
  console.log(Function instanceof Object)//true
  function Foo(params) {}console.log(Object instanceof Foo);//false
Copy the code

Remember that the principle of instance is to determine whether the prototype of a function object is in the prototype chain of the previous example object, so we can easily write the principle and the result.

7. Two interview questions

The first line:

  function A() {}
  A.prototype.n=1;
  var b=new A();
  A.prototype={
    n:2.m:3
  }
  var c=new A();
  console.log(b.n,b.m,c.n,c.m)
Copy the code

Instantiate the object by placing an n attribute on the object. Instantiate the object with an n attribute. Next, A creates A new prototype object for its function object, assigns two properties and instantiates it. This instantiation refers to the prototype object, so our two sample objects refer to two different prototype objects

So the output is:

1 undefined 2 3
Copy the code

The second way:

function F() {}Object.prototype.a = function () {
    console.log('a')}Function.prototype.b = function () {
    console.log('b')}var f = new F();
  f.a();
  f.b();
  F.a();
  F.b();
Copy the code

ToString (); toString(); toString(); toString(); The second one adds a method to Function’s prototype object

F (): f (): f (): f (): f (): f (): f (): f (): f (); Function.prototype.__proto__-> object.prototype.a () F.b(): function.prototype.__proto__ -> object.prototype.a () F.b(): Each Function is an instance object of Function, so F as an instance object has its own prototype chain, and its implicit prototype points to the prototype object that Function’s display prototype points to

Execute context/scope chain/closure

The execution context is used to preprocess THE JS code

The execution context stack is used to manage the execution context

1. Execution context

When JS code is executed, its code location is divided into a global code and the code within the function, so the execution context is divided into the global execution context and the function execution context.

Global execution context

A global execution context is created before executing the global code and the window identifies it as the global execution context; And a preprocessing of global data, which includes:

  • Set the global variable defined by var to undefined and add it to the property of window
  • Declare the function function and add it to the window method
  • This is assigned to window

After the global execution context completes, the code is actually executed

Function execution context

A function execution context is an environment similar to the global execution context, which is used to preprocess local data before the function is executed

  • Parameter variables are assigned as arguments and added as properties of the execution context
  • Argument is assigned to the argument list and added as an attribute of the execution context
  • The local variable defined by var is set to undefined and added as an attribute of the execution context
  • The function assignment declared by function is added as a property of the execution context
  • This is assigned to the object or window of the calling function

After the function context is pointed out, start executing the code in our function body

Whether it is a global execution context or a function execution context, there will be an execution context before their JS code execution, to give our code inside the variable, function, this, etc., declaration assignment, and so on after the operation is finished, the actual execution of the code

2. Execute the context stack

Before global code execution, the JS engine creates a stack to manage all execution context objects

  • Once the global execution context is determined, it is added to the stack
  • When the execution context of a function is determined, it is added to the stack
  • After the function execution context completes, the stack is removed
  • The only thing left on the stack is Window

So the number of execution context objects we have is always n+1, where n is the number of function execution contexts and 1 is the global execution context Window

An interview question:

Problem: Execution results and several execution contexts

 console.log('g begin'+i);
  var i=1;
  foo(i);
  function foo(i) {
    if (i==4) {
      return
    }
    console.log('foo begin:'+i)
    foo(i+1);
    console.log('foo end:'+i)
  }

  console.log('g end:'+i)
Copy the code

Analysis: First this is a recursive function. The execution result is:

  g beginundefined
  foo begin:1
  foo begin:2
  foo begin:3
  foo end:3
  foo end:2
  foo end:1
  g end:1
Copy the code

The function executes four times, plus a global execution context, so there are five execution context objects

3. The scope

To my understanding, a scope is a region of code that can be executed. A scope is static, and its scope is determined when we write the code. One of the biggest functions of scopes is to isolate variables and prevent name-changing conflicts.

There are three types of scopes: global scope, local scope and block scope

** Global scope: ** global scope is the outermost code execution scope, all variables that do not have a direct assignment are automatically declared as global scope; All properties of window objects are globally scoped; The downside of global scope is that too many global scope variables can pollute the global namespace and cause variable conflicts

** Function scope: ** function scope declaration inside the variable, usually only fixed code snippet can access, and function scope is layered, the inner scope can access the outer scope, and the outer scope cannot access the inner scope

** Block-level scopes: ** This is unique to ES6. Block-level scopes can be declared using the new let const directive. Block-level scopes can be created in a function or in a scoped block. The variables declared by let and const do not have an increase in size and may not be declared repeatedly.

4. Scope chain

Scope chain is, in fact, when we are looking for a variable in the current scope, but not the scope of this variable, then the variable is free variables, if can’t find the variable in their scope, will, in turn, to the superior scope search, until the cessation of access to the window, the scope chain is the relationship of layers.

The purpose of a scope chain is to ensure orderly access to all variables and functions that the executing environment has access to.

A scope chain is essentially a list of Pointers to a variable object. A variable object is an object that contains all variables and functions in the execution environment. The scope chain is always preceded by the variable object of the current execution context. The variable object of the global execution context is always the last object in the scope chain

5. The closure

How closures are generated: ** Closures are generated when a nested inner subfunction references variables of the nested outer function.

What exactly are ** closures: are ** closures nested internal functions? I think a closure is actually an object that contains variables that we refer to as external functions (browser debugging comes to this conclusion)

Conditions under which closures are generated:

  • Nested function
  • An inner function references data from an outer function
  • Execute external functions (external functions are not executed, internal functions are not defined, function definitions can generate closures)

Common closures:

  1. Take a function as the return value of another function
function fn1() {
    var a=2;
    function fn2() {
      a++
      console.log(a)
    }
    return fn2
  }
  var f=fn1();// Generate the first closure
  f();/ / 3
  f();/ / 4
  var f2=fn1();// Generate the second closure
  f2();/ / 3
  f2();/ / 4
  fn1()()// Generate a third closure
  fn1()()// Generates a fourth closure
Copy the code
  1. Pass a function as an argument to another function
 function shwDelay(msg,time) {
    setTimeout(() = > {
      console.log(msg)
    }, time);
  }
  shwDelay('123'.1000)
Copy the code

What closures do:

  1. Use variables inside a function (local variables) that live in memory after execution (lengthens the declaration cycle of local variables)
  2. Make it possible to manipulate (read and write) data outside the function into the function itself

Closure lifecycle:

Generated: generated when the nested internal function definition is executed, that is, when the function is executed (variable promotion, function promotion)

Dead: when a nested inner function becomes a junk object (when a reference to this function points to NULL)

Disadvantages of closures:

  1. If a closure function is executed and referenced, it will remain in memory until it is released manually, causing a memory leak

  2. After the function is executed, the local variables of the function are not released, and the memory usage will become longer

    function fnn() {
        var arr=new Array(10000)
        function fnn2() {
          console.log(arr.length)
        }
        return fnn
      }
      var fnn=fnn();
      fnn()
      fnn=null
    Copy the code

The above code uses an array in our closure that takes up a lot of space. If we stop using it, it will stay in memory, so we need to point it to NULL manually. Reclaim our local variables by making internal functions garbage objects

A classic interview question about closures:

  function fun(n, o) {
    console.log(o);
    return {
      fun: function (m) {
        return fun(m, n)
      }
    }
  }
  var a=fun(0); a.fun(1); a.fun(2); a.fun(3);/ / u, 0, 0
  var b=fun(0).fun(1).fun(2).fun(3)/ / u, 0
  var c=fun(0).fun(1); c.fun(2); c.fun(3)/ / u, 0,1,1
Copy the code

6. Memory overflow and leak

** Memory overflow :** Memory overflow occurs when a program runs on more memory than the computer has allocated to it

** Memory leak: ** can be understood as sub-health, and related to the habit of coding, such as occupied memory is not released in time, and memory overflow eventually caused by the situation is memory overflow, avalanche when there is no snowflake innocent.

Common memory leaks are:

  1. Too many local variables
  2. There are no subscription tasks to clean up
  3. closure

Object oriented

1. There are several ways to create objects

  • Object constructor mode, passednew Object
  • Literals create objects
  • Factory mode creates objects (in practice, the literal creation object is optimized to create multiple objects with the same properties and methods)
  • Custom constructor pattern (so that all properties and methods repeat in memory after multiple instantiations)
  • Custom constructors + stereotypes (constructors put attributes, stereotypes put methods)
  • ES6 uses classes to create objects

2. What are the methods of object inheritance

There are actually two broad categories: inheritance in ES5 and inheritance in ES6. Let’s focus on inheritance in ES5

While there are many types of inheritance in ES5, when combined, there is only one, our prototype chain + constructor inheritance (composite inheritance).

Let’s get straight to the idea of one way: It’s essentially giving an instance Object of the parent class to the prototype of the subclass, so our prototype was an instance Object of Object, but now we’re replacing the prototype with an instance Object of the parent class, and the instance Object of the parent class points to the prototype of the method of the parent class, and the prototype of the method of the parent class is an Object, So this operation has no effect except that we get the parent properties and methods, but basically we want to get the methods on the parent prototype. When we’re done with this, we can subclass the method from the parent class; You can now think about where the constructor property points to. If you know about stereotypes, it’s easy to infer that the constructor is pointing to a function object of the parent class. Constructor refers to the parent class because we are on the prototype object and the subclass’s prototype object is the parent class’s prototype object. Therefore, we need to retrieve the missing constructor.

Why not take properties from the parent class’s stereotype methods? Since we use the parent class’s properties in this way, we also need to pass in parameters to initialize the properties when new the parent class instance object, which is quite troublesome, so we introduce constructor inheritance. We get the parent class property by borrowing this.

Let’s go straight to the example code:

 function Person(name,age) {
    this.name=name;
    this.age=age
  }
  Person.prototype.setname=function(name){
    this.name=name
  }
  function Student(name,age,price) {
    Person.call(this,name,age)// Constructor inheritance
    this.price=price
  }

  Student.prototype=new Person()// Prototype chain inheritance
  //Student. Prototype = object.create (Person
  Student.prototype.constructor=Student;/ / retrieve the constructor
  Student.prototype.setPrice=function(price){
    this.price=price
  }
  let stu=new Student('Joe'.'12'.'10000');
  console.log(stu.name,stu.age,stu.price)
Copy the code

Seven. / call/apply/bind

1. Understanding of this object

This is an attribute that performs the above and points to the object on which the method was last called. In real development, the pointer to this can be invoked in four invocation modes. There are also four ways to call a function.

  • Default bindings, which are direct independent calls to functions
  • Implicit binding, call of a function’s method (implicit missing case)
  • Show bindings, called through bind/call/apply
  • The new binding, which is the constructor call

2. The case where the this implicit binding is lost

First of all, what is implicit loss, which means that an implicitly bound method loses its bound object, so it’s bound to the window by default

1. Function alias

  var a=0;
  function foo() {
    console.log(this.a)
  }

  var obj={
    a:1,
    foo
  }
  var bar=obj.foo
  bar()
Copy the code

2. Parameter transfer

 var a=0;
  function foo() {
    console.log(this.a)
  }
  var obj={
    a:1,
    foo
  }
  function bar(fn) {
    fn()
  }
  bar(obj.foo)
Copy the code

Built-in functions

var a=10;
  function foo() {
    console.log(this.a)
  }
  var obj={
    a:1,
    foo
  }
  setTimeout(obj.foo,500);
Copy the code

4. Indirect invocation

 var a = 2;
  function foo() {
    console.log(this.a)
  }
  var obj = {
    a: 3,
    foo
  }
  var p = { a: 4 };
  obj.foo();
  (p.foo = obj.foo)()/ / 2; Call immediately to the window
  p.foo()
Copy the code

3. The difference between call and apply

The form of parameter transfer is different, and the rest is the same.

**apply: ** takes two arguments. The first is a reference to this and the second is a collection with an underlying index, which can be an array or an array of classes. The elements of the collection are passed as arguments to the called function

**call: ** takes several arguments, the first of which is the same as apply, and the rest are passed in one after the other

4. Write call and apply functions by hand

Handwritten call function:

Steps:

1. Check the type of the first parameter

2. Pass the current function as a method to the object

3. Retrieve the argument class array

4. Execute obj. Current function (newarugument) and save the return value

5. Delete the method passed to the object

6. Return the returned value

The code is as follows:

Function.prototype.newCall = function (obj) {
    if (typeofobj ! ="object" || obj == null) { obj = window }
    obj.fn = this
    let newArguments = [];
    for (let i = 1; i < arguments.length; i++) {
      newArguments.push(arguments[i])
    }
    varresult = obj.fn(... newArguments)delete obj.fn
    return result
  }
Copy the code

Handwritten apply function:

The only difference between the apply function and the call function is that it takes two arguments. We can say, well, if there’s no second argument then we just execute the function, and if there’s an argument then we do the argument processing.

The code is as follows:

  Function.prototype.newApply = function (obj, arr) {
    var result;
    if (typeofobj ! ="object" || obj == null) obj = window
    obj.fn = this
    if (arr == null) {
      result = obj.fn()
    } else {
      let newArgument = []
      for (let i = 0; i < arr.length; i++) { newArgument.push(arr[i]) } result = obj.fn(... newArgument) }delete obj.fn;
    return result
  }
Copy the code

5. Write bind

First, we need to understand what bind does and some of its features. The bind function generally returns a function and has the following features:

  1. It has the property of being corrified
  2. The returned function can be new instantiated (the obj object bound to bind is lost after instantiation)

Let’s take a look. In fact, if you’re simply changing this, the inside of Bind isn’t that complicated because it uses apply directly. What matters is how we implement two of its features.

We know that we will return a function internally because we have two arguments that we passed in. We just need to process and concatenate the arguments.

Then we instantiate new, first if we use new, then the function we return inside this will point to the constructor instance, if we don’t use window, so we bind this to apply when it points to the constructor instance, If not, bind to the previous OBJ. Finally, we point the prototype of the function we called to the prototype of the function we returned, so we’re doing an inheritance, and if we instantiate it we can get the data from the Person prototype.

Code implementation:


  Function.prototype.newBind = function (obj) {
    // Determine the incoming object type
    if (typeofobj ! ="object" || obj == null) obj = window
    var that = this
    // External function arguments
    var arr1 = Array.prototype.slice.call(arguments.1);
    var newFun = function () {
      console.log(this)
      var arr2 = Array.prototype.slice.call(arguments);
      // Instantiate class new when judged
      if (this instanceof newFun) {
        that.apply(this, arr1.concat(arr2))
      } else {
        that.apply(obj, arr1.concat(arr2))
      }
    }
    newFun.prototype = that.prototype
    return newFun;
  }

Copy the code

Asynchronous programming

1. Implementation of asynchronous programming

JavaScript asynchrony generally falls into the following categories:

  • Callback functions: Nesting multiple callback functions can create callback hell, which is not good for code maintenance
  • Promise: Chained calls solve the callback hell of callback functions
  • Generator: Asynchronous operations can be performed in a synchronous manner
  • Async function: an automatically executed syntactic sugar for promise and generator implementations that returns promises with a clear structure.

2. Understanding of Promise

First, Promise is a solution to asynchronous programming. It is itself an object that can fetch asynchronous messages, eliminating the callback hell caused by callback functions.

A Promise can be understood as a container that holds the result of an event (usually an asynchronous operation) that will end in the future.

An instance of Promise has three states:

  • Pending
  • Resolved (Completed)
  • Rejected (= rejected)

When you give something to a Promise, its state is “Pending”. When the task is completed, it becomes “Resolved” and when it fails, it becomes “Rejected”

An instance of Promise has two procedures:

  • This is a pity -> phase-resolved song.
  • Pending -> Rejected: Rejected

Notice that this operation is irreversible.

Conclusion:

Promise is a constructor that takes a function as an argument and returns a Promise instance. A Promise instance has three states, pending, Resolved, and Rejected, representing ongoing, successful, and failed, respectively. The instance state can only be changed from “Resolved” or “Rejected” to “Pending”. Once the instance state is changed, it is frozen and cannot be changed.

State changes are implemented through the resolve() and Reject () functions, which can be called after an asynchronous operation to change the state of a Promise instance. The prototype defines a THEN method that registers callbacks for both state changes. This callback is a microtask and is executed at the end of the current event loop.

Note: the code inside the constructor is executed immediately.

3. Understanding async/await

Async /await is a syntactic candy for Generator and Promise. All effects it can achieve can be realized with THEN chains. It is developed to optimize then chains. Async is literally short for ‘asynchronous’ and’ await ‘means to wait, so it makes sense that async is used to declare that a function is asynchronous and’ await ‘is used to wait for an asynchronous method to complete. Of course syntactically forces await to appear only in ASNYC functions.

The async function returns a Promise object. Async functions (including function statements, function expressions, and Lambda expressions) return a Promise object. If a function returns an immediate Promise, async wraps the immediate Promise object with promise.resolve ().

Async returns a Promise, so in cases where the outermost layer cannot await the return value, of course the Promise should be processed the way it is: then() chain, like this:

async function testAsy(){
   return 'hello world'
}
let result = testAsy() 
console.log(result)
result.then(v= >{
    console.log(v)   // hello world
})
Copy the code

What if async does not return a value? It’s easy to imagine that it returns promise.resolve.

4. How do async/await catch exceptions

Use the try.. catch

async function fn(){
    try{
        let a = await Promise.reject('error')}catch(error){
        console.log(error)
    }
}
Copy the code

5. Advantages of async/await versus Promise

  • The code reads more synchronously, and Promise gets rid of callback hell, but the chained calls to THEN carry an additional reading burden

  • Promise passing intermediate values is cumbersome, while async/await is almost synchronous and elegant

  • Error handling is friendly, async/await can be used with mature try/catch, and Promise error catching is very redundant

Garbage collection and memory leaks

1. Browser garbage collection mechanism

1.1 Concept of Garbage Recycling:

** Garbage collection: ** When JavaScript code runs, it needs to allocate memory space to store variables and values. When variables no longer participate in the run, the system needs to reclaim the occupied memory space, which is the garbage collection mechanism.

Recovery mechanism:

  • JavaScript has an automatic garbage collection mechanism, which periodically frees the memory occupied by variables and objects that are no longer used. The principle is to find variables that are no longer used, and then free the memory occupied by them
  • There are two types of variables in JavaScript, local variables and global variables. The life of a global variable lasts until the page is destroyed; The life cycle of a local variable is reclaimed as the function completes execution
  • When a local variable is used by an external function, which is often referred to as a closure, when the function is finished, the external variable of the function still refers to the local variable of the internal function, and the local variable is still in use, so it will not be recycled, so we need to set null manually.

1.2 Methods of garbage recycling

There are two common garbage collection methods used by browsers: tag scavenging and reference counting

1. Mark clearing:

A common garbage collection method used by browsers to mark a variable as it enters the execution environment. Variables marked as entering the environment cannot be collected because they are in use. When a variable leaves the environment, it is marked as leaving the environment, and the variable marked as leaving the environment is freed from memory.

2. Reference count:

This is used relatively infrequently. Reference counting tracks the number of times a value is referenced, plus 1 if a variable assigns a reference type to that variable. If the variable containing the reference gets another value. The number of references to this value is -1. When the number of references to this value is 0, it is reclaimed.

Function func4 () {const c = {} // The reference count of the type variable c is 0 let d = c // the reference count of c is 1 let e = c // the reference count of C is 2 d = {} // d no longer references c, c's reference count is reduced to 1, e = null // E no longer references C, c's reference count is reduced to 0, will be reclaimed}Copy the code

Note that one drawback of this garbage collection approach is the problem of circular references, such as:

Obj1 and obj2 refer to each other, and the count cannot be zero, so we need to manually free memory.

function fun() { let obj1 = {}; let obj2 = {}; obj1.a = obj2; // obj1 references obj2 obj2.a = obj1; // obj2 references obj1}Copy the code

1.3 Reduce recycling

While automatic garbage collection can be done by browsers, garbage collection can be costly when code is complex, so it should be minimized.

  • ** Optimizes arrays: ** The easiest way to empty an array is to assign it a value of [], but at the same time a new empty object is created. The length of the array can be set to 0 to clear the array.

  • **object**** optimization: **object reuse as far as possible, for no longer used objects, it is set to null, as soon as possible to be recycled.

  • ** Function optimization: ** Function expressions in the loop, if reusable, try to put outside the function.

2. Factors that cause memory leaks

Memory leaks can occur in four ways:

  • ** Unexpected global variable: ** Accidentally created a global variable by using an undeclared variable, leaving it in memory and unable to be reclaimed.

  • ** Forgotten timers or callback functions: ** Sets the setInterval timer and forgets to cancel it. If the loop function has a reference to an external variable, that variable is left in memory and cannot be reclaimed.

  • ** Out-of-DOM references: ** gets a reference to a DOM element that is deleted and cannot be reclaimed because references to this element are kept forever.

  • ** Closures: ** Improper use of closures, resulting in some variables being left in memory.