Javascript Interview Core Test Site (Basic Edition)
Introduction
Javascript is the focus of front-end interviews. This article focuses on sorting out the common knowledge points in Javascript, and then analyzes some easy-to-appear topics. Limited to the length of the article, it is impossible to explain all the knowledge points. This article only lists some important and difficult points. If you want to know more, please click on my blog .
1. the variable type
1. JS data type classification
According to the transmission method of variable type in JavaScript, it is divided into basic data type and reference data type. The basic data types include Undefined, Null, Boolean, Number, String, and Symbol (new in ES6, representing unique values), while reference data types are collectively called Object objects, including objects, arrays, and functions.
There are differences in the way parameters are passed:
- If the parameter of the function is a simple type, a copy of the value type will be passed to the inside of the function, and the inside of the function will not affect the parameter variables passed outside the function.
- If a parameter is a reference type, the address value of the reference type will be copied to the parameter passed into the function, and the internal modification of the function will affect the reference object passed in the parameter.
Topic: The difference between primitive types and reference types
Basic types and reference types are stored in different locations in memory. Basic types are directly stored in the stack, while objects of reference types are stored in the heap. At the same time, a pointer is stored in the stack, and this pointer points to the entity in the heap. starting position. Let's take a look at the main differences between the two through a small topic:
// basic type
var a = 10
var b = a
b = 20
console.log(a) // 10
console.log(b) // 20
In the above code, ab is a value type, and the two modify the assignment respectively without any influence on each other. Look again at the reference type example:
// reference type
var a = {x: 10, y: 20}
var b = a
b.x = 100
b.y = 200
console.log(a) // {x: 100, y: 200}
console.log(b) // {x: 100, y: 200}
In the above code, ab is a reference type. After executing b = a, modify the attribute value of b, and the value of a also changes. Because a and b are both reference types and point to the same memory address, that is, both refer to the same value, so when b modifies the attribute, the value of a changes accordingly
2. Judgment of data type
1)typeof
typeof returns a string representing the data type . The returned results include: number, boolean, string, symbol, object, undefined, function and other 7 data types, but cannot judge null, array, etc.
typeof Symbol(); // symbol is valid
typeof ''; // string is valid
typeof 1; // number is valid
typeof true; //boolean valid
typeof undefined; //undefined is valid
typeof new Function(); // function is valid
typeof null; //object is invalid
typeof [] ; //object is invalid
typeof new Date(); //object is invalid
typeof new RegExp(); //object is invalid
2)instanceof
instanceof is used to determine whether A is an instance of B. The expression is: A instanceof B, if A is an instance of B, it returns true, otherwise it returns false. The instanceof operator is used to test whether an object has a constructor's prototype property in its prototype chain, but it cannot detect null and undefined
[] instanceof Array; //true
{} instanceof Object;//true
new Date() instanceof Date;//true
new RegExp() instanceof RegExp//true
null instanceof Null//error
undefined instanceof undefined//error
3)constructor
The constructor function is very similar to instanceof. But the constructor detection Object is not the same as instanceof, and can also handle the detection of basic data types.
However, the constructor of the function is unstable. This is mainly reflected in the rewriting of the prototype of the class. In the process of rewriting, it is very likely that the previous constructor will be overwritten, so the detected result will be inaccurate.
4)Object.prototype.toString.call()
Object.prototype.toString.call() is the most accurate and common way .
Object.prototype.toString.call('') ; // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
3. Shallow copy and deep copy
Shallow copy only copies the pointer to an object, not the object itself, the old and new objects still share the same memory .
Shallow copy implementation (see shallow copy and deep copy for details ):
- Object.assign(): It should be noted that when the target object has only one layer, it is a deep copy
- Array.prototype.concat()
- Array.prototype.slice()
A deep copy is to copy all the reference structures of the data when copying the data . Simply put, there are two data structures in memory that are identical and independent of each other, and the reference type is copied instead of just copying its reference relationship.
Implementation of deep copy:
- The popular library lodash also provides _.cloneDeep for deep copying
- jQuery provides a $.extend that can be used for deep copying
- JSON.parse(JSON.stringify())
- Handwritten recursive method
The principle of recursive implementation of deep copy: to copy a piece of data, we must traverse its properties. If the properties of the object are still objects, continue to use this method, and so on.
//Define the function function to detect the data type
function checkedType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
// Implement deep clone --- object/array
function clone(target) {
/ / Determine the data type of the copy
//Initialize the variable result to become the final cloned data
let result,
targetType = checkedType(target)
if (targetType === 'Object') {
result = {}
} else if (targetType === 'Array') {
result = []
} else {
return target
}
// Traverse the target data
for (let i in target) {
//Get each value of the traversed data structure.
let value = target[i]
/ / Determine whether each value in the target structure exists an object/array
if (checkedType(value) === 'Object' || checkedType(value) === 'Array') {
//Objects/Arrays are nested within Objects/Arrays
//Continue to traverse to get the value
result[i] = clone(value)
} else {
//The value obtained is a basic data type or a function.
result[i] = value
}
}
return result
}
2. Scope and Closures
1. Execution context and execution stack
The execution context is the abstract concept of the environment in which the current JavaScript code is parsed and executed. Any code running in JavaScript runs in the execution context.
The life cycle of an execution context consists of three phases: creation phase → execution phase → recycling phase, and we focus on the creation phase.
The creation phase (when a function is called, but before any of its internal code is executed) does three things:
- Create a variable object: first initialize the function's argument arguments, lift the function declaration and variable declaration.
- Create a scope chain: described below
- Make sure this points to: will be introduced below
function test(arg){
// 1. The formal parameter arg is "hi"
// 2. Because function declarations have higher priority than variable declarations, arg is function at this time
console.log(arg);
var arg = 'hello'; // 3.var arg variable declaration is ignored, arg = 'hello' is executed
function arg(){
console.log('hello world')
}
console.log(arg);
}
test('hi');
/* output:
function arg() {
console.log('hello world');
}
hello
*/
This is because when the function is executed, a new private scope is first formed, and then the following steps are followed:
- If there is a formal parameter, assign a value to the formal parameter first
- Perform pre-interpretation in private scope, function declaration has higher priority than variable declaration, and finally the latter will be overwritten by the former, but can be reassigned
- Code in private scope is executed from top to bottom
There are many functions, and there are multiple function execution contexts. Each time a function is called, a new execution context is created. How to manage so many execution contexts created?
The JavaScript engine creates the execution stack to manage the execution context. The execution stack can be considered as a stack structure that stores function calls, following the principle of first-in, last-out .
From the above flowchart, we need to remember a few key points:
- JavaScript executes on a single thread, and all code is queued for execution.
- When the browser starts executing global code, it first creates a global execution context and pushes it to the top of the execution stack.
- Whenever execution of a function is entered, the function's execution context is created and pushed onto the top of the execution stack. After the execution of the current function is completed, the execution context of the current function is popped off the stack and waits for garbage collection.
- The browser's JS execution engine always accesses the execution context at the top of the stack.
- There is only one global context, and it is popped from the stack when the browser is closed.
2. Scope and scope chain
ES6 comes JavaScript with global scope, function scope and block scope (new in ES6). We can understand it this way: the scope is an independent site, so that variables will not be leaked and exposed. That is to say, the biggest use of scope is to isolate variables, and variables with the same name in different scopes will not conflict .
Before introducing the scope chain, we must first understand free variables. In the following code, console.log(a) needs to get the a variable, but a is not defined in the current scope (compare b). A variable that is not defined in the current scope, this becomes a free variable.
var a = 100
function fn() {
var b = 200
console.log(a) // where a is a free variable here
console.log(b)
}
fn()
How to get the value of the free variable - look to the parent scope (the parent scope that created the function) . What if the parent doesn't have one? Look up layer by layer until you find the global scope and still don't find it, then give up. This layer-by-layer relationship is the scope chain.
function F1() {
var a = 100
return function () {
console.log(a)
}
}
function F2(f1) {
var a = 200
console.log(f1())
}
var f1 = F1()
F2(f1) // 100
In the above code, the value of the free variable a is searched from the function F1 instead of F2, because when the free variable is searched from the scope chain, it is based on the scope chain when the function is defined, not when the function is executed.
3. What is a closure
The concept of closure is also a relatively abstract concept in JavaScript. I personally understand that a closure is a function in a function (other languages cannot do this), the function inside can access the variables of the outside function, and the outside variables belong to the internal function. part.
The role of closures:
- Use closures to access variables in functions.
- Variables can be kept in memory for a long time, and the life cycle is relatively long .
Closures cannot be abused, otherwise it will cause memory leaks and affect the performance of web pages. After the closure is used up, to release the resource immediately, point the reference variable to null.
There are two main application scenarios for closures:
- Functions are passed as parameters (see the Scope section for an example)
- function as return value (example below)
function outer() {
var num = 0 //internal variable
return function add() {
//By returning the add function by return, it can be accessed outside the outer function.
num++ //The internal function has a reference as part of the add function
console.log(num)
}
}
var func1 = outer() //
func1() //Actually call the add function, output 1
func1() //output 2
var func2 = outer()
func2() // output 1
func2() // output 2
4.This comprehensive analysis
First understand a very important concept - the value of this can only be confirmed when it is executed, and it cannot be confirmed when it is defined! Why - because this is part of the execution context, and the execution context needs to be determined before the code is executed, not when it is defined. See the following example:
// case 1
function foo() {
console.log(this.a) //1
}
var a = 1
foo()
// case 2
function fn(){
console.log(this);
}
var obj={fn:fn};
obj.fn(); //this->obj
// case 3
function CreateJsPerson(name,age){
//this is an instance of the current class p1
this.name=name; //=>p1.name=name
this.age=age; //=>p1.age=age
}
var p1=new CreateJsPerson("Yin Huazhi",48);
// case 4
function add(c, d){
return this.a + this.b + c + d;
}
var o = {a:1, b:3};
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
// case 5
<button id="btn1">arrow function this</button>
<script type="text/javascript">
let btn1 = document.getElementById('btn1');
let obj = {
name: 'kobe',
age: 39,
getName: function () {
btn1.onclick = () => {
console.log(this);//obj
} };
}
};
obj.getName();
</script>
Next, we explain the above situations one by one
- For calling foo directly, no matter where the foo function is placed, this must be window
- For obj.foo(), we only need to remember that whoever calls the function is this, so in this scenario, this in the foo function is the obj object
- In the constructor mode, this in this.xxx=xxx that appears in the class (in the function body) is an instance of the current class
- call, apply and bind: this is the first parameter
- The arrow function this points to: the arrow function does not have its own this, to see if there is a function in the outer layer, if there is, the this of the outer function is the this of the inner arrow function, if not, then this is the window.
3. Asynchronous
1. Synchronous vs Asynchronous
Synchronization, my understanding is a way of linear execution, the flow of execution cannot be spanned. For example, when you are eating after talking, and you are looking at your phone after eating, you have to wait for the last thing to finish before executing the next thing.
Asynchronous is a way of parallel processing. You don't have to wait for a program to finish executing, and you can perform other tasks. For example, when a person eats, looks at the mobile phone, and talks, this is the way of asynchronous processing. Results that are processed asynchronously in a program are usually processed using callback functions.
// Synchronize
console.log(100)
alert(200);
console.log(300) //100 200 300
// async
console.log(100)
setTimeout(function(){
console.log(200)
})
console.log(300) //100 300 200
2. Asynchronous and single-threaded
The fundamental reason why JS needs to be asynchronous is that JS runs on a single thread, that is, it can only do one thing at the same time, and cannot "do two things at the same time". In order to take advantage of the computing power of multi-core CPUs, HTML5 proposes the Web Worker standard, which allows JavaScript scripts to create multiple threads, but the sub-threads are completely controlled by the main thread and must not operate the DOM. So, this new standard doesn't change the single-threaded nature of JavaScript.
An Ajax request takes 5 seconds due to the slow network. If it is synchronization, the page will be stuck here for 5 seconds and can't do anything. If it is asynchronous, it is much better. Waiting for 5 seconds will wait, and other things will not be delayed. As for the 5-second waiting, the network speed is too slow, not because of JS.
3. Front-end asynchronous scenarios
Front-end using asynchronous scenarios
- Timed tasks: setTimeout, setInterval
- Network request: ajax request, dynamic loading
- event binding
4. Event Loop
A complete Event Loop process can be summarized into the following stages:
- At the beginning of the execution stack empty, we can think of the execution stack as a stack structure that stores function calls, following the principle of first-in, last-out . The micro queue is empty, and there is only one script (the whole code) in the macro queue.
- The global context (script tag) is pushed onto the execution stack, synchronizing code execution. In the process of execution, it will determine whether it is a synchronous task or an asynchronous task. By calling some interfaces, new macro-task and micro-task can be generated, and they will be pushed into their respective task queues. After the synchronization code is executed, the script script will be removed from the macro queue. This process is essentially the process of executing and dequeuing the macro-task of the queue.
- In the previous step, we dequeued a macro-task, and in this step, we dealt with a micro-task. But it should be noted that: when the macro-task is dequeued, the tasks are executed one by one; and when the micro-task is dequeued, the tasks are executed one by one. Therefore, we deal with the micro queue step, which will execute the tasks in the queue one by one and dequeue it until the queue is emptied.
- Perform rendering operations, update the interface
- Check if there is a web worker task, if so, process it
- The above process repeats itself until both queues are emptied
Next, let's look at an example to introduce the above process:
Promise.resolve().then(()=>{
console.log('Promise1')
setTimeout(()=>{
console.log('setTimeout2')
},0)
})
setTimeout(()=>{
console.log('setTimeout1')
Promise.resolve().then(()=>{
console.log('Promise2')
})
},0)
The final output is Promise1, setTimeout1, Promise2, setTimeout2
- After the synchronization task (which belongs to the macro task) of the initial execution stack is completed, it will check whether there is a micro-task queue, which exists in the above question (there is only one), and then execute all tasks in the micro-task queue to output Promise1, and at the same time it will Generate a macro task setTimeout2
- Then go to check the macro task queue, the macro task setTimeout1 executes the macro task setTimeout1 before setTimeout2, and outputs setTimeout1
- When the macro task setTimeout1 is executed, the micro-task Promise2 will be generated and put into the micro-task queue. Then, all tasks in the micro-task queue will be cleared first, and Promise2 will be output.
- After clearing all the tasks in the micro task queue, it will go to the macro task queue to get another one, this time setTimeout2 is executed
4. Prototype chain and inheritance
1. Prototypes and Prototype Chains
Prototype: In JavaScript, a prototype is a prototype object that represents the relationship between types.
Prototype chain: Everything in JavaScript is an object, and there is a relationship between objects and objects, and they do not exist in isolation. The inheritance relationship between objects, in JavaScript, points to the parent class object through the prototype object until it points to the Object object, which forms a chain pointed to by the prototype, which is called the prototype chain in professional terms.
var Person = function() {
this.age = 18
this.name = 'anonymous'
}
var Student = function() {}
//Create inheritance relationship, parent class instance as child class prototype
Student.prototype = new Person()
var s1 = new Student()
console.log(s1)
Prototype diagram:
When trying to get a property of an object, if the object itself does not have this property, it will look for it __proto__
(that is, the prototype of its constructor). If the top layer is not found all the time, then it will fail and return undefined. What is the top layer -Object.prototype.__proto__ === null
2. Inheritance
Introduce several common inheritance methods (for more information, please click the six common inheritance methods in JavaScript ):
- Prototype chain + borrowed constructor combined inheritance
function Parent(value) {
this.val = value
}
Parent.prototype.getValue = function() {
console.log(this.val)
}
function Child(value) {
Parent.call(this, value)
}
Child.prototype = new Parent()
const child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
The core of the above inheritance method is to Parent.call(this)inherit subclass, and then change the prototype of the new Parent()subclass to inherit the functions of the parent class.
The advantage of this inheritance method is that the constructor can pass parameters, it will not share the reference property with the parent class, and the functions of the parent class can be reused, but there is also a disadvantage that the parent class constructor is called when inheriting the parent class function, resulting in The prototype of the subclass has more unnecessary properties of the parent class, which is a waste of memory.
- Parasitic composition inheritance: This inheritance method optimizes the previous composition inheritance
function Parent(value) {
this.val = value
}
Parent.prototype.getValue = function() {
console.log(this.val)
}
function Child(value) {
Parent.call(this, value)
}
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true
}
})
const child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
The core of the above inheritance implementation is to assign the prototype of the parent class to the subclass, and set the constructor to the subclass, which not only solves the problem of useless parent class attributes, but also correctly finds the constructor of the subclass.
- Inheritance of classes in ES6
The class keyword was introduced in ES6. Class can implement inheritance through the extends keyword, and can also define static methods of the class through the static keyword. This is much clearer and more convenient than ES5's implementation of inheritance by modifying the prototype chain. It should be noted that the class keyword is just syntactic sugar for prototypes, and JavaScript inheritance is still implemented based on prototypes .
class Parent {
constructor(value) {
this.val = value
}
getValue() {
console.log(this.val)
}
}
class Child extends Parent {
constructor(value) {
super(value)
this.val = value
}
}
let child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
The core of class implementation inheritance is to use extends to indicate which parent class inherits from, and super must be called in the subclass constructor, because this code can be seen as Parent.call(this, value).
5. DOM operation and BOM operation
1. DOM manipulation
When the web page is loaded, the browser will create the document object model (DOM) of the page. We can think that the DOM is the HTML structure recognized by JS, a common JS object or array. Next we introduce common DOM operations:
- Adding Nodes and Moving Nodes
var div1 = document.getElementById('div1')
// add new node
var p1 = document.createElement('p')
p1.innerHTML = 'this is p1'
div1.appendChild(p1) // add the newly created element
// Move existing nodes. Note that this is "moving", not copying
var p2 = document.getElementById('p2')
div1.appendChild(p2)
- get parent element
var div1 = document.getElementById('div1')
var parent = div1.parentElement
- get child element
var div1 = document.getElementById('div1')
var child = div1.childNodes
- delete node
var div1 = document.getElementById('div1')
var child = div1.childNodes
div1.removeChild(child[0])
2. DOM event model and event flow
The DOM event model is divided into capturing and bubbling . When an event occurs, it is propagated between child and parent elements. This propagation is divided into three stages.
(1) Capture phase: the phase in which events are propagated from the window object to the target node from top to bottom;
(2) Target stage: the stage where the real target node is processing the event;
(3) Bubbling stage: the stage in which events are propagated from the target node to the window object from bottom to top.
The specific process of DOM event capture
The capture is from top to bottom, events first go from the window object, then to the document (object), then to the html tag (getting the html tag via document.documentElement), then the body tag (getting the body tag via document.body), then It is passed down layer by layer according to the ordinary html structure, and finally reaches the target element.
Next, let's look at an example of event bubbling:
<div id="outer">
<div id="inner"></div>
</div>
......
window.onclick = function() {
console.log('window');
};
document.onclick = function() {
console.log('document');
};
document.documentElement.onclick = function() {
console.log('html');
};
document.body.onclick = function() {
console.log('body');
}
outer.onclick = function(ev) {
console.log('outer');
};
inner.onclick = function(ev) {
console.log('inner');
};
How to stop bubbling?
Prevents events from bubbling up to the parent element via the event.stopPropagation()method, preventing any parent event handlers from being executed.
We can add event.stopPropagation()this sentence to the click event of the inner element in the above example to prevent the execution of the parent event, and finally print only 'inner'.
inner.onclick = function(ev) {
console.log('inner')
ev.stopPropagation()
}
3. Event delegation (event delegation)
Since the event will be propagated up to the parent node in the bubbling stage, the listener function of the child node can be defined on the parent node, and the listener function of the parent node can uniformly handle the events of multiple child elements. This method is called event delegation.
We set a scene, the following code, one <div>
contains several <a>
, and can continue to increase. So how to quickly and easily <a>bind events for all?
<div id="div1">
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
<a href="#">a4</a>
</div>
<button>Click to add an a tag</button>
<a>
If you bind an event to each tag one by one, it will consume a lot of memory. With the help of event proxy, we only need to bind a method to the parent container div, so that no matter which descendant element is clicked, the click behavior of the parent container will be triggered according to the transmission mechanism of bubbling propagation, and then the corresponding method will be executed. , depending on the event source, we can know who clicked and do different things.
var div1 = document.getElementById('div1')
div1.addEventListener('click', function (e) {
// e.target can monitor which element triggers the click event
var target = e.target
if (e.nodeName === 'A') {
// clicked on an <a> element
alert(target.innerHTML)
}
})
Finally, the advantages of using a proxy are as follows:
- make code concise
- Reduce browser memory usage
4. BOM operation
BOM (Browser Object Model) is the setting and obtaining of some information of the browser itself, such as obtaining the width and height of the browser, and setting which address to let the browser jump to.
- window.screen object: contains information about the user's screen
- window.location object: used to get the address (URL) of the current page and redirect the browser to a new page
- window.history object: forward and backward browsing history, etc.
- window.navigator object: often used to obtain browser information, mobile access, etc.
Get the width and height of the screen
console.log(screen.width)
console.log(screen.height)
Get URL, protocol, path, parameters, hash, etc.
// For example, the current URL is https://juejin.im/timeline/frontend?a=10&b=10#some
console.log(location.href) // https://juejin.im/timeline/frontend?a=10&b=10#some
console.log(location.protocol) // https:
console.log(location.pathname) // /timeline/frontend
console.log(location.search) // ?a=10&b=10
console.log(location.hash) // #some
In addition, there are also calls to forward and backward functions of the browser, etc.
history.back()
history.forward()
Get browser characteristics (commonly known as UA) and then identify the client, such as judging whether it is a Chrome browser
var ua = navigator.userAgent
var isChrome = ua.indexOf('Chrome')
console.log(isChrome)
5. Ajax and cross domain
Ajax is a technology for asynchronously requesting data, which is very helpful for improving user experience and program performance.
Simply put, Ajax loads background data through asynchronous requests and renders it on the web page without needing to refresh the page. Common application scenarios include form verification whether the login is successful, Baidu search drop-down box prompts, and express tracking number query. The purpose of Ajax is to improve the user experience and reduce the amount of network data transmission .
How to write XMLHttpRequest without any library
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
// The function here is executed asynchronously
if (xhr.readyState == 4) {
if (xhr.status == 200) {
alert(xhr.responseText)
}
}
}
xhr.open("GET", "/api", false)
xhr.send(null)
Because browsers have a same-origin policy for security reasons. That is, if there is a difference in the protocol, domain name, or port, it is cross-domain, and the Ajax request will fail.
So why is this mechanism introduced for security reasons ? In fact, it is mainly used to prevent CSRF attacks. To put it simply, CSRF attacks use the user's login state to initiate malicious requests.
Then let's consider a question, the request is cross-domain, so is the request sent ? The request must have been sent, but the browser intercepted the response.
Several common cross-domain solutions (for details, please refer to the implementation principles of nine cross-domain methods (full version) ):
- JSONP: <script>Unrestricted tags using the same-origin policy, but only supports GET requests
- CORS: The key to realizing CORS communication is the backend, Access-Control-Allow-Originwhich can . It is a well-respected cross-domain solution, much simpler than JSONP.
- Node middleware proxy or nginx reverse proxy: mainly through the same-origin policy, the server is not restricted
6. Storage
Difference between sessionStorage, localStorage and cookies
- Common ground: They are all saved on the browser side, and they all follow the same-origin policy.
- The difference: the difference between the life cycle and the scope
Scope: localStorage can read/modify the same localStorage data under the same protocol, same hostname, and same port. sessionStorage is a bit more strict than localStorage, in addition to protocol, host name, port, it also requires the same window (that is, the browser tab)
Life cycle: localStorage is a persistent local storage, the data stored in it will never expire, and the only way to make it disappear is to delete it manually; while sessionStorage is a temporary local storage, it is a session-level storage, when When the session ends (the page is closed), the stored content is also released.
6. Modularization
Introduction to several common modular specifications (for details, please click Front-end Modular Explanation (full version) ):
- The CommonJS specification is mainly used for server-side programming. Loading modules is synchronous, which is not suitable for a browser environment, because synchronous means blocking loading, and browser resources are loaded asynchronously, so there is an AMD CMD solution.
- The AMD specification loads modules asynchronously in a browser environment, and multiple modules can be loaded in parallel. However, the development cost of the AMD specification is high, the code is difficult to read and write, and the semantics of the module definition method are not smooth.
- The CMD specification is very similar to the AMD specification. Both are used for browser programming, relying on proximity, delayed execution, and can be easily run in Node.js. However, depending on SPM packaging, the loading logic of the module is biased
- At the level of language standards, ES6 implements module functions, and the implementation is quite simple. It can completely replace CommonJS and AMD specifications and become a common module solution for browsers and servers.