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:
- If both parties have the same data type, compare the content directly
- Return true if you are comparing null and undefined
- If it’s Number and String, convert String to Number
- If Boolean and Number, convert Boolean to Number
- 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:
- Convert a reference type value to the original value: ToPrimitive()
- Convert values to numbers, ToNumber()
- 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:
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
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
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
- 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:
- Create a new object, obj
- Points the implicit stereotype of an object to the stereotype object of the constructor
- Call the constructor with apply (change this to obj)
- 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
- Pop () and push() tail operations, delete and add
- Shift () and unshift() headers, delete and add
- Sort (), a function that takes two arguments and returns an array by subtracting two arguments
- Reserve () reverses an array, which also returns an array, changing it
- Concat (), concatenates two arrays, returns the concatenated array without changing the original array
- Slice (), which takes a portion of an array and returns it, without affecting the original array
- Splice (), which can delete, replace, or insert one or more elements of an array, return the array, and alter the original array
- The filter() function returns the filtered array without changing the original array
- The map() function iterates through the array without changing the original array
- 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
- For in gets the key name of the object, and for of gets the key of the object
- 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
- 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:
- Create an XmlHttpRequest object
- Create an Http request (you can set the request mode, address, and asynchrony)
- Add information and listener functions (such as adding request headers and listening for XHR status)
- 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:
- Itself is targeted at MVC programming, not in line with the tide of front-end MVVM
- Developed based on native XHR, the architecture of XHR itself is unclear
- Does not conform to the principle of separation of concerns
- 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:
- Initiates an XMLHttpRequest request from the browser
- The Node sends an HTTP request
- Supporting Promise API
- Client support prevents CSRF
- Provides some interfaces for concurrent requests
- Intercept requests and responses
- Transform request and response data
- Cancel the request
- 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:
- 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)
- 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)
- 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
- Use setTimeout delay: Set a timer to delay loading JS script files
- 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:
- Create a new object
- 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. - This in the constructor refers to the object and executes
- 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 (instead
Array.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.assign
The 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 directlyfn.test2()
, first look in the sample object, find no, and then pass__proto__
This property is found in the prototype object. performfn.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 objectfn.test3
After 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:
- 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
- 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:
- Use variables inside a function (local variables) that live in memory after execution (lengthens the declaration cycle of local variables)
- 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:
-
If a closure function is executed and referenced, it will remain in memory until it is released manually, causing a memory leak
-
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:
- Too many local variables
- There are no subscription tasks to clean up
- closure
Object oriented
1. There are several ways to create objects
- Object constructor mode, passed
new 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:
- It has the property of being corrified
- 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.