author :Jake Zhang https://juejin.cn/post/6844904200917221389
I just want to have a face CV The engineer , The interviewer asked me to challenge the rocket engineer , In addition, this year's situation is even worse Two men
, But no matter how difficult it is to live on , I still need to keep looking for a job . In the recent interview, I have been summing up , Every time I come back from the interview, I will come back , The following is the interview knowledge I met these days . But today's topic is written in the title 66 strip JavaScript Knowledge point , from the shallower to the deeper , For a week , Every time (zhěng) God (lǐ) whole (bù) The reason is ( yì)10 strip ( qiú) Left (diǎn) Right (zàn), I hope it can be helpful to those who are looking for a job , If there is something wrong in the text , Also please indicate .
The Internet :
Performance related
In addition, I am also sorting out a more comprehensive set of interview questions , Let's give you a preview :
Let's get to the point :
See my previous article for details :「 Front end package 」 Probably the most thorough JavaScript Data type details
JavaScript Altogether 8 Type of data , Among them is 7 Basic data types :Undefined、Null、Boolean、Number、String、Symbol(es6 newly added , Represents a unique value ) and BigInt(es10 newly added );
1 Types of reference data ——Object(Object It is essentially composed of a set of unordered name value pairs ). It contains function、Array、Date etc. .JavaScript No mechanism for creating custom types is supported , And all the values will eventually be the above 8 One of the data types .
Raw data type : Directly stored in Stack (stack) in , Small occupation space 、 Fixed size , Belongs to frequently used data , So it's stored in the stack .
Reference data type : At the same time, it is stored in Stack (stack) and Pile up (heap) in , Occupy a large space 、 Size is not fixed . Reference data types store pointers in the stack , The pointer points to the starting address of the entity in the heap . When the interpreter looks for a reference value , Will first retrieve its address in the stack , Get the address and get the entity from the heap .
&&
It's called logic and , Finds the first virtual expression in its operand and returns it , If no virtual expression is found , Returns the last true expression . It uses a short circuit to prevent unnecessary work .||
It's called logic or , Finds the first true expression in its operand and returns it . This also uses a short circuit to prevent unnecessary work . In support of ES6 Before default function arguments , It is used to initialize the default parameter values in the function .!!
Operator to cast the value on the right to a Boolean value , This is also a simple way to convert a value to a Boolean value .stay JS There are only three types of conversion in , Namely :
null and underfined No, .toString Method
There are also some operators that have implicit conversions , No expansion here , Can own Baidu 00
(1)typeof
typeof For primitive types , except null Can show the right type
console.log(typeof 2); // number console.log(typeof true); // boolean console.log(typeof 'str'); // string console.log(typeof []); // object [] The data type of the array is in typeof Is interpreted as object console.log(typeof function(){}); // function console.log(typeof {}); // object console.log(typeof undefined); // undefined console.log(typeof null); // object null The data type of is typeof Interpreted as object
typeof For objects , All but functions are displayed object, So typeof We can't judge exactly what kind of variable it is , So I want to judge the correct type of an object , Consider using instanceof
(2)instanceof
instanceof Can correctly judge the type of object , Because the internal mechanism is to determine whether the type can be found in the prototype chain of the object prototype.
console.log(2 instanceof Number); // false console.log(true instanceof Boolean); // false console.log('str' instanceof String); // false console.log([] instanceof Array); // true console.log(function(){} instanceof Function); // true console.log({} instanceof Object); // true // console.log(undefined instanceof Undefined); // console.log(null instanceof Null);
You can see the direct literal value to judge the data type ,instanceof Can accurately determine the reference data type (Array,Function,Object), And the basic data type cannot be instanceof Accurate judgment .
Let's take a look instanceof stay MDN Explanation in :instanceof Operator is used to test whether an object has a constructor in its prototype chain prototype attribute . It means to judge whether the object is a certain data type ( Such as Array) Example , Focus on whether an object is an instance of a data type . The literal value here is ,2, true ,'str' Not the instance , So the judgment value is false.
(3)constructor
console.log((2).constructor === Number); // true console.log((true).constructor === Boolean); // true console.log(('str').constructor === String); // true console.log(([]).constructor === Array); // true console.log((function() {}).constructor === Function); // true console.log(({}).constructor === Object); // true
There's a pit here , If I create an object , Change its prototype ,constructor It will become unreliable
function Fn(){}; Fn.prototype=new Array(); var f=new Fn(); console.log(f.constructor===Fn); // false console.log(f.constructor===Array); // true
(4)Object.prototype.toString.call() Use Object Prototype methods of objects toString , Use call Change the crown prince for a civet cat , To borrow Object Of toString Method
var a = Object.prototype.toString; console.log(a.call(2)); console.log(a.call(true)); console.log(a.call('str')); console.log(a.call([])); console.log(a.call(function(){})); console.log(a.call({})); console.log(a.call(undefined)); console.log(a.call(null));
js The built-in objects in are mainly those that exist in the global scope before the program is executed js Some global value properties defined by 、 Functions and constructors used to instantiate other objects Number object . In general, we often use global variable values NaN、undefined, Global functions such as parseInt()、parseFloat() The construct used to instantiate an object Make functions, such as Date、Object etc. , There are also single built-in objects that provide mathematical calculations, such as Math object .
Knowledge points involved :
Global objects ( global objects ) Or standard built-in objects , Do not mix " Global object (global object)" confusion . The global object here is to say in Objects in global scope . Other objects in the global scope can be created by the user's script or provided by the host program . Classification of standard built-in objects (1) Value attribute , These global properties return a simple value , These values have no properties or methods of their own . for example Infinity、NaN、undefined、null Literal (2) Function attribute , Global functions can be called directly , There is no need to specify the owning object when calling , After execution, the result is returned directly to the caller . for example eval()、parseFloat()、parseInt() etc. (3) The basic object , Basic objects are the basis for defining or using other objects . Basic objects include general objects 、 Function objects and error objects . for example Object、Function、Boolean、Symbol、Error etc. (4) Number and date objects , Used to represent numbers 、 Dates and objects that perform mathematical calculations . for example Number、Math、Date (5) character string , Object used to represent and manipulate strings . for example String、RegExp (6) Indexable collection objects , These objects represent a collection of data sorted by index values , Including arrays and type arrays , And objects of class array structure . for example Array (7) Collection objects using keys , These collection objects use keys when storing data , Supports iteration of elements in insertion order . for example Map、Set、WeakMap、WeakSet (8) Vector set ,SIMD The data in a vector set is organized into a data sequence . for example SIMD etc. (9) Structured data , These objects are used to represent and manipulate structured buffer data , Or use JSON Encoded data . for example JSON etc. (10) Control abstract objects for example Promise、Generator etc. (11) Reflection for example Reflect、Proxy (12) internationalization , To support multilingual processing ECMAScript The object of . for example Intl、Intl.Collator etc. (13)WebAssembly (14) other for example arguments
For details, please refer to :《 Classification of standard built-in objects 》
《JS Summary of all built-in object properties and methods 》
Variables that have been declared in the scope but not yet assigned , yes undefined. contrary , Variables not yet declared in scope , yes undeclared Of .
about undeclared References to variables , The browser will report a reference error , Such as ReferenceError: b is not defined . But we can use typ eof To avoid error reporting , Because for undeclared( perhaps not defined ) Variable ,typeof Returns the "undefined".
First Undefined and Null It's all basic data types , Each of these two basic data types has only one value , Namely undefined and null.
undefined The meaning of representation is undefined , null It means empty object ( It's not a real object , Please look at the following Be careful !). When a general variable is declared but not defined, it will return undefined,null It is mainly used to assign values to variables that may return objects , As initialization .
Actually null Not object , although typeof null Will be output object, But it's just JS There is a long history Bug. stay JS In the original version of 32 Bit system , For performance reasons, use low-level storage variables for type information ,000 The beginning represents the object , However null It's all zero , So it's wrong to say object . Although the current internal type determination code has changed , But for this Bug But it has been handed down all the time .
undefined stay js Chinese is not a reserved word , This means that we can use undefined As a variable name , This is very dangerous , it It will affect our response to undefined Value judgment . But there are some ways we can get secure undefined value , for instance void 0.
When we use typeof When judging ,Null Typing returns “object”, This is a problem left over by history . When we use double equal When comparing two types of values, it returns true, Using three equal signs returns false.
For details, please refer to :
《JavaScript In depth understanding of undefined And null》
{} Of valueOf The result is {} ,toString As the result of the "[object Object]" [] Of valueOf The result is [] ,toString As the result of the ""
Scope : Scope is the area where variables are defined , It has a set of rules for accessing variables , This set of rules govern how the browser engine depends on variables in the current scope as well as nested scopes ( identifier ) Find variables .
Scope chain : The role of scope chain is to ensure orderly access to all variables and functions that have access to the execution environment , Through the scope chain , We can access variables in the outer environment and function .
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 . Before the scope chain The end is always the variable object of the current execution context . Global execution context variable object ( That is, global objects ) Always the last object in the scope chain .
When we look for a variable , If not found in the current execution environment , We can look backward along the scope chain .
The creation process of scope chain is related to the establishment of execution context ....
For details, please refer to :《JavaScript In depth understanding of the scope chain 》
You can also look at my article :「 Front end package 」 Go deep into JavaScript Scope ( chain ) Knowledge points and closures
We usually create objects directly in the form of literals , But this kind of creation method is suitable for creating a large number of similar objects , There's a lot of repetitive code . but js Different from general object-oriented languages , stay ES6 It didn't have the concept of a class before . But we can use functions to simulate , Thus, reusable objects are produced How it was created , There are several ways I've learned :
(1) The first is the factory model , The main working principle of factory mode is to use functions to encapsulate the details of creating objects , In order to achieve the purpose of reuse by calling functions . But it has a big problem that the created objects can't be associated with a certain type , It simply encapsulates the reuse code , Instead of establishing a relationship between objects and types .
(2) The second is the constructor pattern .js Each function in can be used as a constructor , As long as a function is passed through new To invoke the , So we can call it a constructor . Executing a constructor first creates an object , Then point the prototype of the object to the constructor prototype attribute , Then it will execute this Point to this object , Finally, the entire function is executed , If the return value is not an object , The new object is returned . because this The value of points to the newly created object , So we can use this Assign a value to an object . The advantage of the constructor pattern over the factory pattern is , The object created is linked to the constructor , So we can use prototypes to identify the types of objects . But one drawback of constructors is that , Create an object that is unnecessary , Because in js The middle function is also an object , So if an object property contains a function , So every time we create a new function object , Wasted unnecessary memory space , Because functions are universal to all instances .
(3) The third pattern is the prototype pattern , Because every function has a prototype attribute , This property is an object , It contains properties and methods that can be shared by all instances created through constructors . So we can use prototype objects to add common properties and methods , To achieve code reuse . This approach is relative to the constructor pattern , The reuse of function objects is solved . But there are also some problems with this model , One is that there is no way to initialize values by passing in parameters , The other is if there is a reference type such as Array So the value of the , Then all instances will share an object , A change in the value of a reference type affects all instances .
(4) The fourth pattern is a combination of constructor pattern and prototype pattern , This is the most common way to create custom types . Because there are some problems in using constructor pattern and prototype pattern separately , So we can combine these two patterns , Initializing the properties of an object through a constructor , The reuse of function method is realized by prototype object . This method solves the shortcomings of the two modes when they are used alone , But there's one thing that's not enough , Because two different patterns are used , So the encapsulation of the code is not good enough .
(5) The fifth pattern is the dynamic prototype pattern , This pattern moves the creation of the prototype method assignment to the inside of the constructor , By judging whether an attribute exists , You can implement the effect of assigning a prototype object only once when the function is called for the first time . This is a good way to encapsulate the above mixed mode .
(6) The sixth pattern is the parasitic constructor pattern , The implementation of this mode is basically the same as the factory mode , My understanding of this pattern is , It's mainly based on an existing type , Extend the instantiated object when instantiating . In this way, you don't have to modify the original constructor , It also achieves the purpose of extending objects . One of its drawbacks is the same as the factory model , Unable to implement object recognition .
Well, what I've learned so far is that .
For details, please refer to :《JavaScript Deep understanding of object creation 》
I know js There are several ways to implement inheritance in :
(1) The first is to implement inheritance in the form of prototype chain , But the disadvantage of this implementation is , When you include data of reference type , Will be shared by all instance objects , It is easy to cause confusion in revision . Also, you can't pass parameters to a supertype when you create a subtype .
(2) The second way is to use the borrowing constructor , This is achieved by calling super type constructors in subtype functions , This method solves the problem of not passing parameters to a supertype , But it has a problem that it can't realize the reuse of function method , And the method subtype defined by the supertype prototype has no access to .
(3) The third way is combinatorial inheritance , Composite inheritance is a way to combine prototype chains and borrowing constructors . By borrowing the constructor to implement the inheritance of type properties , Methods are inherited by setting the prototype of a subtype to an instance of a supertype . This method solves the problem of using the above two modes separately , But because we are prototyped with instances of supertypes , So I called the constructor of the superclass twice , This creates a lot of unnecessary properties in the prototype of the subtype .
(4) The fourth way is archetypal inheritance , The main idea of prototype inheritance is to create new objects based on existing objects , The principle of implementation is , Pass an object into the function , It then returns an object prototype of this object . The idea of inheritance is not to create a new type , It's just a simple inheritance of an object ,ES5 As defined in Object.create() Methods are the implementation of prototype inheritance . The disadvantages are the same as the prototype chain .
(5) The fifth way is parasitic inheritance , The idea of parasitic inheritance is to create a function that encapsulates the inheritance process , By passing in an object , And then make a copy of the object , Then the object is extended , Finally, return this object . This extension process can be understood as a kind of inheritance . The advantage of this kind of inheritance is to implement inheritance on a simple object , If the object is not our custom type . The disadvantage is that there is no way to reuse functions .
(6) The sixth way is parasitic combinatorial inheritance , The disadvantage of composite inheritance is that it uses instances of supertypes as prototypes of subtypes , This leads to the addition of unnecessary prototype properties . The way to parasitically combine inheritance is to use a copy of the prototype of a supertype as the prototype of a subtype , This avoids creating unnecessary properties .
For details, please refer to :《JavaScript The inheritance of deep understanding 》
{ this.name = name; } Person.prototype.sayName = function() { console.log("My name is " + this.name + "."); }; function Student(name, grade) { Person.call(this, name); this.grade = grade; } Student.prototype = Object.create(Person.prototype); Student.prototype.constructor = Student; Student.prototype.sayMyGrade = function() { console.log("My grade is " + this.grade + "."); };
See my previous article for details :「 Front end package 」 Get a thorough understanding of JavaScript Medium this、call、apply and bind
stay js We use the constructor to create a new object , Inside each constructor there is a prototype Property value , This property value is a pair of like , This object contains properties and methods that can be shared by all instances of the constructor . When we create an object with a constructor , Inside the object Will contain a pointer , This pointer points to the constructor prototype The value of the property , stay ES5 This pointer in is called the prototype of the object . Generally speaking, we You should not be able to get this value , But now it's all implemented in browsers proto Property to let us access this property , But we'd better not use this Attributes , Because it's not specified in the specification .ES5 There's a new Object.getPrototypeOf() Method , We can use this method to get the information about The archetype of the elephant .
When we access the properties of an object , If this property does not exist inside this object , Then it will look for this property in its prototype object , This prototype object is again It will have its own prototype , So I kept looking for it , That's the concept of the prototype chain . The end of the prototype chain is usually Object.prototype So this is It's why our new object can be used toString() And so on .
characteristic :
JavaScript Objects are passed by reference , None of the new object entities we create has its own prototype copy . When we modify the prototype , And Its related objects will also inherit this change .
Reference article :
《JavaScript Deep understanding of prototype and prototype chain 》
You can also see what I wrote :「 Front end package 」 In depth understanding of JavaScript Prototypes and prototype chains
A closure is a function that has access to a variable in the scope of another function , The most common way to create a closure is to create another function within one function , The function created can be Access to the local variable of the current function .
Closures have two common uses .
function a(){ var n = 0; function add(){ n++; console.log(n); } return add; } var a1 = a(); // Be careful , The function name is just an identifier ( Pointer to function ), and () It's the executive function ; a1(); //1 a1(); //2 Second call n Variables are still in memory
In fact, the essence of closure is a special application of scope chain , As long as you understand the creation process of the scope chain , You can understand the implementation principle of closures .
DOM The object of a document is a model , It refers to treating a document as an object , This object mainly defines the methods and interfaces for handling web page content .
BOM Refers to the browser object model , It refers to treating the browser as an object , This object mainly defines the method and interface to interact with browser .BOM The core is window, and window Objects have dual roles , It is both through js An interface for accessing browser windows , Another Global( overall situation ) object . This means any object defined in the web page , Variables and functions , All exist as an attribute or method of the global object .window Objects contain locati on object 、navigator object 、screen Object and other sub objects , also DOM The most fundamental object of document Object is also BOM Of window Yes Children of the elephant .
Related information :
《DOM, DOCUMENT, BOM, WINDOW What's the difference? ?》
《Window object 》
《DOM And BOM What are the differences , What's the connection ?》
《JavaScript Learning summary ( 3、 ... and )BOM and DOM Detailed explanation 》
event It's the interaction that happens when the user operates the web page or some operation of the web page itself , There are three event models in modern browsers .
Related information :
《 One DOM Element binding multiple events , Bubble or capture first 》
Event delegation In essence, it takes advantage of the browser event bubble mechanism . Because the event will be uploaded to the parent node during the bubbling process , And the parent node can get through the event object The target node , Therefore, we can define the listening function of the child node on the parent node , The listener function of the parent node uniformly handles the events of multiple child elements , This approach is called event broker .
With the event broker, we don't have to bind a listening event for each child element , This reduces memory consumption . And using event proxy, we can also implement dynamic binding of events , For example, a new child node is added , We don't need to add a listening event to it alone , The events it takes place will be handled by the listener in the parent element .
Related information :
《JavaScript Detailed explanation of the event entrustment 》
When event It happened in DOM Time on element , The event does not happen entirely on that element . stay “ When an event occurs DOM Time on element , The event does not happen entirely on that element .
There are three stages of event communication :
When an event occurs DOM Time on element , The event does not happen entirely on that element . In the capture phase , Events from window Start , Up to the element that triggered the event .window----> document----> html----> body \----> Target element
Suppose that HTML structure :
<div class="grandparent"> <div class="parent"> <div class="child">1</div> </div> </div>
Corresponding JS Code :
function addEvent(el, event, callback, isCapture = false) { if (!el || !event || !callback || typeof callback !== 'function') return; if (typeof el === 'string') { el = document.querySelector(el); }; el.addEventListener(event, callback, isCapture); } addEvent(document, 'DOMContentLoaded', () => { const child = document.querySelector('.child'); const parent = document.querySelector('.parent'); const grandparent = document.querySelector('.grandparent'); addEvent(child, 'click', function (e) { console.log('child'); }); addEvent(parent, 'click', function (e) { console.log('parent'); }); addEvent(grandparent, 'click', function (e) { console.log('grandparent'); }); addEvent(document, 'click', function (e) { console.log('document'); }); addEvent('html', 'click', function (e) { console.log('html'); }) addEvent(window, 'click', function (e) { console.log('window'); }) });
addEventListener
Method has a third optional parameter useCapture
, The default value is false
, The event will occur during the bubbling phase , If true, The event will occur in the capture phase . If you click child
Elements , It will print separately on the console window
,document
,html
,grandparent
and parent
, This is it. Event capture .
Event bubbling is the opposite of event capture , The current element ---->body \----> html---->document \---->window
. When an event occurs DOM Time on element , The event does not happen entirely on that element . In bubbling stage , Event Bubbling , Or it happens to its parents , My grandparents , Grandparents' parents , Until arrival window until .
Suppose that HTML structure :
<div class="grandparent"> <div class="parent"> <div class="child">1</div> </div> </div>
Corresponding JS Code :
function addEvent(el, event, callback, isCapture = false) { if (!el || !event || !callback || typeof callback !== 'function') return; if (typeof el === 'string') { el = document.querySelector(el); }; el.addEventListener(event, callback, isCapture); } addEvent(document, 'DOMContentLoaded', () => { const child = document.querySelector('.child'); const parent = document.querySelector('.parent'); const grandparent = document.querySelector('.grandparent'); addEvent(child, 'click', function (e) { console.log('child'); }); addEvent(parent, 'click', function (e) { console.log('parent'); }); addEvent(grandparent, 'click', function (e) { console.log('grandparent'); }); addEvent(document, 'click', function (e) { console.log('document'); }); addEvent('html', 'click', function (e) { console.log('html'); }) addEvent(window, 'click', function (e) { console.log('window'); }) });
addEventListener
Method has a third optional parameter useCapture
, The default value is false
, The event will occur during the bubbling phase , If true, The event will occur in the capture phase . If you click child
Elements , It will print separately on the console child
,parent
,grandparent
,html
,document
and window
, This is it. Event Bubbling .
(1) Create a new node
createDocumentFragment() createElement() // Create a specific element createTextNode() // Create a text node
(2) add to 、 remove 、 Replace 、 Insert
appendChild(node) removeChild(node) replaceChild(,old) insertBefore(new,old)
(3) lookup
getElementById(); getElementsByName(); getElementsByTagName(); getElementsByClassName(); querySelector(); querySelectorAll();
(4) Attribute operation
getAttribute(key); setAttribute(key, value); hasAttribute(key); removeAttribute(key);
Related information :
《DOM summary 》
《 Native JavaScript Of DOM Operation summary 》
《 Native JS in DOM Node related API Collection 》
//(1) matching 16 Base color value var color = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g; //(2) Match date , Such as yyyy-mm-dd Format var date = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/; //(3) matching qq Number var qq = /^[1-9][0-9]{4,10}$/g; //(4) Cell phone number regular var phone = /^1[34578]\d{9}$/g; //(5) User name regular var username = /^[a-zA-Z\$][a-zA-Z0-9_\$]{4,16}$/; //(6)Email Regular var email = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/; //(7) ID number (18 position ) Regular var cP = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; //(8)URL Regular var urlP= /^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/; // (9)ipv4 Address regular var ipP = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; // (10)// The license plate number is regular var cPattern = /^[ Beijing, Tianjin, Shanghai, Chongqing, Hebei, Henan, Yunnan, Liaoning, Heilongjiang, Hunan, Anhui, Shandong, new Jiangsu, Zhejiang, Jiangxi, Hubei, Guangxi, Gansu, Shanxi, Inner Mongolia, Shaanxi, Jilin, Fujian, Guizhou, Guangdong, Qinghai Tibet, Sichuan, Ningxia and Hainan A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9 Hang the school police in Hong Kong and Macao ]{1}$/; // (11) Strong password ( Must contain a combination of upper and lower case letters and numbers , Special characters cannot be used , The length is in 8-10 Between ):var pwd = /^(?=.\d)(?=.[a-z])(?=.[A-Z]).{8,10}$/
I am right. ajax The understanding is , It's a way of asynchronous communication , By directly by js Script to server http signal communication , And then according to the data returned by the server , Update the corresponding part of the page , Instead of refreshing the entire page .
//1: establish Ajax object var xhr = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');// compatible IE6 Up to //2: To configure Ajax Request address xhr.open('get','index.xml',true); //3: Send a request xhr.send(null); // Rigorous writing //4: Monitor requests , Accept response xhr.onreadysatechange=function(){ if(xhr.readySate==4&&xhr.status==200 || xhr.status==304 ) console.log(xhr.responsetXML) }
$.ajax({ type:'post', url:'', async:ture,//async asynchronous sync Sync data:data,// in the light of post request dataType:'jsonp', success:function (msg) { }, error:function (error) { } })
// promise Encapsulation implementation : function getJSON(url) { // Create a promise object let promise = new Promise(function(resolve, reject) { let xhr = new XMLHttpRequest(); // Create a new one http request xhr.open("GET", url, true); // Set state listener function xhr.onreadystatechange = function() { if (this.readyState !== 4) return; // When a request succeeds or fails , change promise The state of if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } }; // Set error listener function xhr.onerror = function() { reject(new Error(this.statusText)); }; // Set the data type of the response xhr.responseType = "json"; // Set the request header information xhr.setRequestHeader("Accept", "application/json"); // send out http request xhr.send(null); }); return promise; }
js Loading 、 Parsing and execution can block the rendering process of the page , So we hope js Scripts can delay loading as much as possible , Improve the rendering speed of the page .
Several ways I've learned are :
Related information :
《JS Several ways to delay loading 》
《HTML 5 <script>
async
attribute 》
My understanding of modules is , A module is a set of methods to implement a specific function . In the beginning ,js It only implements some simple functions , So there's no concept of modules , But as the program gets more complex , Modular development of code is becoming more and more important .
Because of its independent scope , The most primitive way to write it is to use functions as modules , Several functions as a module , However, it is easy to pollute global variables in this way dye , And there is no connection between modules .
After that, the object writing method is put forward , By using a function as an object , This solves some shortcomings of using functions as modules directly , But this approach will expose There are all the module members , External code can modify the values of internal properties .
Now the most commonly used method is to execute functions immediately , The private scope of module is established by using closure , At the same time, it will not pollute the global scope .
Related information :《 On Modular Development 》
《Javascript Modular programming ( One ): Module writing 》
《 Front-end modularization :CommonJS,AMD,CMD,ES6》
《Module The grammar of 》
js Now, there are four kinds of module loading schemes :
There are two main differences between them .
The timing of module execution ,AMD After the dependent module is loaded, the dependent module is executed directly , The execution order of dependent modules is not necessarily the same as the order we write . and CMD Do not execute after the dependent module is loaded , It's just a download , Wait until all the dependent modules are loaded , Enter callback function logic , encounter require sentence Only when the corresponding module is executed , In this way, the execution order of modules is consistent with the order in which we write .
define(function(require, exports, module) { var a = require("./a"); a.doSomething(); // Omitted here 100 That's ok var b = require("./b"); // Dependence can be written nearby b.doSomething(); // ... }); // AMD Default recommendation define(["./a", "./b"], function(a, b) { // Dependencies must be written at the beginning a.doSomething(); // Omitted here 100 That's ok b.doSomething(); // ... });
Related information :
《 Front-end modularization ,AMD And CMD The difference between 》
CommonJS
The output of the module is a copy of the value ,ES6 The module outputs a reference to a value .CommonJS
The output of the module is of value , in other words , Once a value is output , Changes within the module do not affect this value .ES6 The operation mechanism of the module and CommonJS Dissimilarity .JS When the engine statically analyzes the script , Module load command encountered import, It will generate a read-only reference . Wait until the script actually executes , According to this read-only reference , Go to the loaded module to get the value .
CommonJS
Modules are run time loaded ,ES6 Module is a compile time output interface .CommonJS
Modules are objects , That is to load the whole module before input , Generate an object , Then read the method from the object , This load is called “ Load at run time ”. and ES6 Module is not an object , Its external interface is just a static definition , It will be generated during the static parsing phase of the code .require.js The core principle of is to create... Dynamically script Scripts to introduce modules asynchronously , And then for each script load Event monitoring , If every script is loaded , Call the callback function again .```
For details, please refer to :《requireJS Analysis of the usage and principle of 》
《requireJS What is the core principle of ?》
《requireJS Principle analysis 》
JavaScript One of the characteristics of language is single thread , That is, only one thing can be done at a time .
“JavaScript The single thread , Related to its use . As a browser scripting language ,JavaScript Its main purpose is to interact with users , And operation DOM. This determines that it can only be a single thread , Otherwise, it will bring complicated synchronization problems . such as , Assume JavaScript There are two threads at the same time , A thread in a DOM Add content on node , Another thread deleted this node , Which thread should the browser follow ?
therefore , To avoid complexity , From the birth ,JavaScript It's a single thread , This has become the core feature of the language , It won't change in the future .
js There are many tasks during code execution , These tasks are divided into two categories :
When we open the website , The rendering process of a web page is a lot of synchronization tasks , For example, rendering of page skeleton and page elements . And tasks like loading pictures and music take up a lot of resources , It's asynchronous tasks ., We use a map to illustrate :
Let's explain this picture :
Event Table
And register functions .Event Table
Will move this function into Event Queue
.Event Queue
Read the corresponding function , Enter the main thread execution .Event Loop
( The event loop ). When is the main thread execution stack empty ?js The engine exists monitoring process
process , It will continuously check whether the main thread execution stack is empty , Once it's empty , Will go Event Queue
There's a check to see if there's a function waiting to be called .
That's all js The overall process of operation
Note that in addition to synchronous and asynchronous tasks , Tasks can be further subdivided into macrotask( Macro task ) and microtask( Micro task ),js The engine will give priority to micro tasks
Micro tasks include promise The callback 、node Medium process.nextTick 、 Yes Dom Change the monitoring of MutationObserver. Macro tasks include script Script execution 、setTimeout ,setInterval ,setImmediate A class of timed events , What's more I/O operation 、UI Shading Dye, etc .
How to answer in the interview ? The following is my personal recommendation :
Finally, we can test the harvest with the following question :
setTimeout(function() { console.log(1) }, 0); new Promise(function(resolve, reject) { console.log(2); resolve() }).then(function() { console.log(3) }); process.nextTick(function () { console.log(4) }) console.log(5)
The first round : The main thread starts executing , encounter setTimeout, take setTimeout The callback function of the macro task queue , It's going down new Promise Execute now , Output 2,then The callback function is dropped to the micro task queue , And go on with it , encounter process.nextTick, Also throw the callback function to the task queue , And go on with it , Output 5, When all synchronization tasks are completed, check whether there are micro tasks that can be executed , Found to have then Functions and nextTick Two micro tasks , Which one to execute first ?process.nextTick The specified asynchronous task always occurs before all asynchronous tasks , So first execute process.nextTick Output 4 And then execute then Output function 3, The first round of execution ended . The second round : Start with the macro task queue , Find out setTimeout Callback , Output 1 completion of enforcement , So the result is 25431
Related information :
《 Browser event loop mechanism (event loop)》
《 Detailed explanation JavaScript Medium Event Loop( The event loop ) Mechanism 》
《 What is? Event Loop?》
《 This time, , Understand thoroughly JavaScript Execution mechanism 》
arguments Object is a collection of parameter values passed in a function . It's an array like object , Because it has a length attribute , We can use array index notation arguments[1] To access individual values , But it has no built-in methods in the array , Such as :forEach、reduce、filter and map.
We can use Array.prototype.slice take arguments Object to an array .
{ return Array.prototype.slice.call(arguments); }
Be careful : Not in arrow function arguments object .
{ return arguments; } const two = function () { return arguments; } const three = function three() { return arguments; } const four = () => arguments; four(); // Throws an error - arguments is not defined
When we call a function four when , It throws out one ReferenceError: arguments is not defined error
. Use rest grammar , Can solve this problem .
four = (...args) => args;
This will automatically put all parameter values into the array .
b
It becomes a global variable ?{ let a = b = 0; } myFunc();
The reason is that assignment operators are evaluated from right to left . This means that when multiple assignment operators appear in an expression , They are evaluated from right to left . So that's what the code above looks like :
{ let a = (b = 0); } myFunc();
First , expression b = 0 evaluation , In this case b No statement . therefore ,JS The engine creates a global variable outside of this function b, Expression after b = 0 The return value of is 0, And assign new local variables a.
We can solve this problem by declaring variables before assigning values .
{ let a,b; a = b = 0; } myFunc();
v8 The garbage collection mechanism of is based on generational collection mechanism , This mechanism is based on the generational hypothesis , This hypothesis has two characteristics , First, the new object is easy to die early , The other is that the immortal will live longer . Based on this hypothesis ,v8 The engine divides memory into new and old generations . Newly created objects or objects that have experienced only one garbage collection are called the new generation . Objects that have been garbage collected many times are referred to as the "old generation" . The new generation is divided into From and To Two spaces ,To It's usually idle . When From When the space is full Scavenge Algorithm for garbage collection . When we execute the garbage collection algorithm, the application logic will stop , Wait until the garbage collection is over . This algorithm is divided into three steps : (1) First check From The living object of space , If the object survives, it is judged whether the object meets the conditions for promotion to the old generation , If you meet the requirements, you will be promoted to the older generation . If not, move To Space . (2) If the object doesn't survive , Then release the space of the object . (3) The final will be From Space and To Space roles are exchanged . There are two conditions for the new generation to be promoted to the old generation : (1) The first is to judge whether the object has been passed once Scavenge Recycling . If you have experienced , Then the object is changed from From Space is copied into the old generation ; If you don't experience , Copy to To Space . (2) The second is To Whether the memory usage ratio of space exceeds the limit . When the object from From Space copied to To When space , if To Space use exceeds 25%, Then the object is promoted directly to the old generation . Set up 25% The main reason is that after the algorithm is finished , When the two spaces are finished, they will switch positions , If To Space memory is too small , Will affect subsequent memory allocation . In the old generation, mark clearing method and label compression method were used . Mark clearing first marks the surviving objects in memory , After marking, clear the unmarked objects . Because the mark will cause a lot of memory fragmentation after clearing , It's not easy to allocate memory later . Therefore, to solve the problem of memory fragmentation, the label compression method is introduced . Because the logic of the application will be suspended during garbage collection , For the new generation method, due to the small memory , Each pause will not be too long , But for the older generation, each garbage collection takes a long time , A pause can have a big impact . To solve this problem V8 The incremental marking method is introduced , Divide a pause into multiple steps , Each time a small step is completed, let the running logic execute for a while , So it's running alternately .
Related information :
《 In depth understanding of V8 The principle of garbage collection 》
《JavaScript Garbage collection in 》
setInterval
Timer , And forget to cancel it , If the loop function has a reference to an external variable , Then this variable will be left in memory all the time , And can't be recycled .Related information :
《JavaScript Memory leak tutorial 》
《4 class JavaScript Memory leaks and how to avoid them 》
《 Eradicate js The occurrence of four types of memory leaks in 》
《javascript Typical memory leaks and chrome How to find out 》
following 38~46 The bar is ECMAScript 2015(ES6) The basic knowledge of the middle school entrance examination
ECMAScript Is the standard for scripting languages , It means JavaScript follow ECMAScript Specification changes in standards , Because it is JavaScript The blueprint of .
ECMAScript and Javascript, It's essentially about a language , One is the name of the language itself , One is language constraints It's just invention JavaScript The man who (Netscape company ), Give it to me ECMA(European Computer Manufacturers Association), This man sets his standards , Because there were java The language , I want to emphasize that this thing is to make ECMA The rules of this man , So that's why this amazing thing was born , The name of this thing is called ECMAScript.
javaScript = ECMAScript + DOM + BOM( Self belief is a kind of generalized JavaScript)
ECMAScript what did you say? JavaScript What to do !
JavaScript( The narrow sense JavaScript) Ask about everything ECMAScript Can I do this ! I'm wrong if I can't ! Yes, I'm right !
—— A sudden sensation JavaScript Good no dignity , Why do we need to get individuals to restrain ourselves ,
That man was created, or wronged , I was created because I had to be restrained JavaScript.
var
,let
and const
What's the difference ?var The declared variables are mounted on the window On , and let and const Declared variables will not :
a = 100; console.log(a,window.a); // 100 100 let b = 10; console.log(b,window.b); // 10 undefined const c = 1; console.log(c,window.c); // 1 undefined
var Declaration variable has variable promotion ,let and const No variable promotion :
.log(a); // undefined ===> a Declared not assigned , Get by default undefined value var a = 100; console.log(b); // Report errors :b is not defined ===> Can't find b This variable let b = 10; console.log(c); // Report errors :c is not defined ===> Can't find c This variable const c = 10;
let and const Declare chunk scope
(1){ var a = 100; let b = 10; } console.log(a); // 100 console.log(b) // Report errors :b is not defined ===> Can't find b This variable ------------------------------------------------------------- if(1){ var a = 100; const c = 1; } console.log(a); // 100 console.log(c) // Report errors :c is not defined ===> Can't find c This variable
Under the same scope let and const Cannot declare a variable with the same name , and var Sure
a = 100; console.log(a); // 100 var a = 10; console.log(a); // 10 ------------------------------------- let a = 100; let a = 10; // Console error :Identifier 'a' has already been declared ===> identifier a Has been declared .
Temporary deadband
a = 100; if(1){ a = 10; // Exists in the current block scope a Use let/const In case of declaration , to a assignment 10 when , Only variables will be found in the current scope a, // And then , It's not time to make a statement , So the console Error:a is not defined let a = 1; }
const
const a = 100; const list = []; list[0] = 10; console.log(list); // [10] const obj = {a:100}; obj.name = 'apple'; obj.a = 10000; console.log(obj); // {a:10000,name:'apple'}
The syntax of arrow function expression is more concise than function expression , And there's no one of its own this,arguments,super or new.target
. Arrow function expressions are more suitable for places where anonymous functions are needed , And it cannot be used as a constructor .
var getCurrentDate = function (){ return new Date(); } //ES6 Version const getCurrentDate = () => new Date();
In this case ,ES5 Version has function(){}
Declaration and return keyword , These two keywords are needed to create functions and return values . In arrow function version , We just need () Brackets , Unwanted return sentence , Because if we have only one expression or value to return , The arrow function will have an implicit return .
function greet(name) { return 'Hello ' + name + '!'; } //ES6 Version const greet = (name) => `Hello ${name}`; const greet2 = name => `Hello ${name}`;
We can also use the same parameters as function expressions and function declarations in arrow functions . If we have an argument in an arrow function , You can omit the parenthesis .
getArgs = () => arguments const getArgs2 = (...rest) => rest
Arrow function not accessible arguments object . So call the first getArgs Function throws an error . contrary , We can use rest Parameter to get all the parameters passed in the arrow function .
data = { result: 0, nums: [1, 2, 3, 4, 5], computeResult() { // there “this” refer to “data” object const addAll = () => { return this.nums.reduce((total, cur) => total + cur, 0) }; this.result = addAll(); } };
Arrow function does not have its own this value . It captures the this value , In this example ,addAll Function will be copied computeResult Methods this value , If we declare arrow functions in the global scope , be this The value is window object .
class (class) Is in JS A new method of writing constructors in . It's a syntactic sugar that uses constructors , Use in the bottom is still prototype and prototype based inheritance .
function Person(firstName, lastName, age, address){ this.firstName = firstName; this.lastName = lastName; this.age = age; this.address = address; } Person.self = function(){ return this; } Person.prototype.toString = function(){ return "[object Person]"; } Person.prototype.getFullName = function (){ return this.firstName + " " + this.lastName; } //ES6 Version class Person { constructor(firstName, lastName, age, address){ this.lastName = lastName; this.firstName = firstName; this.age = age; this.address = address; } static self() { return this; } toString(){ return "[object Person]"; } getFullName(){ return `${this.firstName} ${this.lastName}`; } }
Override method and inherit from another class .
Employee.prototype = Object.create(Person.prototype); function Employee(firstName, lastName, age, address, jobTitle, yearStarted) { Person.call(this, firstName, lastName, age, address); this.jobTitle = jobTitle; this.yearStarted = yearStarted; } Employee.prototype.describe = function () { return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`; } Employee.prototype.toString = function () { return "[object Employee]"; } //ES6 Version class Employee extends Person { //Inherits from "Person" class constructor(firstName, lastName, age, address, jobTitle, yearStarted) { super(firstName, lastName, age, address); this.jobTitle = jobTitle; this.yearStarted = yearStarted; } describe() { return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`; } toString() { // Overriding the "toString" method of "Person" return "[object Employee]"; } }
So how do we know it uses prototypes internally ?
{ } function AnotherSomething(){ } const as = new AnotherSomething(); const s = new Something(); console.log(typeof Something); // "function" console.log(typeof AnotherSomething); // "function" console.log(as.toString()); // "[object Object]" console.log(as.toString()); // "[object Object]" console.log(as.toString === Object.prototype.toString); // true console.log(s.toString === Object.prototype.toString); // true
Related information :
《ECMAScript 6 Realized class, Yes JavaScript What's the point of front-end development ?》
《Class Basic syntax 》
The template string is in the JS A new method of creating string in . We can string templates by using backquotes .
var greet = 'Hi I\'m Mark'; //ES6 Version let greet = `Hi I'm Mark`;
stay ES5 We need to use some escape characters to achieve multi line effect , The template string doesn't need to be so cumbersome :
var lastWords = '\n' + ' I \n' + ' Am \n' + 'Iron Man \n'; //ES6 Version let lastWords = ` I Am Iron Man `;
stay ES5 In the version , We need to add \n To add a new line to the string . In template string , We don't need to .
function greet(name) { return 'Hello ' + name + '!'; } //ES6 Version function greet(name) { return `Hello ${name} !`; }
stay ES5 In the version , If you need to add an expression or value to a string , You need to use +
Operator . In template string s in , We can use ${expr}
Embed an expression , This makes it ES5 Cleaner version .
Object destructor is a new way to get or extract values from objects or arrays 、 A simpler approach . Suppose you have the following objects :
employee = { firstName: "Marko", lastName: "Polo", position: "Software Developer", yearHired: 2017 };
Get properties from object , The early method was to create a variable with the same name as the object property . This method is troublesome , Because we're going to create a new variable for each property . Suppose we have a big object , It has many properties and methods , Extracting attributes in this way can be cumbersome .
firstName = employee.firstName; var lastName = employee.lastName; var position = employee.position; var yearHired = employee.yearHired;
Using deconstruction syntax is much simpler :
{ firstName, lastName, position, yearHired } = employee;
We can also alias properties :
{ firstName: fName, lastName: lName, position, yearHired } = employee;
Of course, if the property value is undefined when , We can also specify default values :
{ firstName = "Mark", lastName: lName, position, yearHired } = employee;
Set
object , How it works ?Set Object allows you to store unique values of any type , Whether it's the original value or the object reference .
We can use Set Constructor creation Set example .
set1 = new Set(); const set2 = new Set(["a","b","c","d","d","e"]);
We can use add Method direction Set Add a new value to the instance , because add Method returns Set object , So we can use it again in a chained way add. If a value already exists in Set In the object , Then it will no longer be added .
set2.add(); set2.add("g").add("h").add("i").add("j").add("k").add("k"); // After a “k” Will not be added to set In the object , Because it already exists
We can use has Methods to check Set Is there a specific value in the instance .
set2.has() // true set2.has("z") // true
We can use size Attribute gets Set Length of instance .
set2.size
have access to clear Methods to remove Set Data in .
set2.clear();
We can use Set Object to remove duplicate elements from an array .
numbers = [1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 5]; const uniqueNums = [...new Set(numbers)]; // [1,2,3,4,5,6,7,8]
And then there is WeakSet
, And Set
similar , It's also a set of values that don't repeat . however WeakSet
Members of can only be objects , It can't be any other type of value .WeakSet
The objects in are all weak references , That is, garbage collection mechanism does not consider WeakSet
Reference to the object .
Proxy Used to modify the default behavior of certain operations , It's equivalent to making changes at the language level , So it belongs to “ Metaprogramming ”, That is to program the programming language .
Proxy Can be interpreted as , Set up a layer in front of the target object “ Intercept ”, External access to the object , All must be intercepted through this layer first , So it provides a mechanism , It can filter and rewrite external access .Proxy The original meaning of this word is agent , It's used here to show that it comes from “ agent ” Some operations , It can be translated into “ Agent ”.
High energy warning , following 47~64 The bar is JavaScript It is difficult to realize the advanced knowledge and related handwriting , Ladies and gentlemen, please take your time
const EventUtils = { // Depending on your ability, use dom0||dom2||IE The way To bind events // Add event addEvent: function(element, type, handler) { if (element.addEventListener) { element.addEventListener(type, handler, false); } else if (element.attachEvent) { element.attachEvent("on" + type, handler); } else { element["on" + type] = handler; } }, // Remove events removeEvent: function(element, type, handler) { if (element.removeEventListener) { element.removeEventListener(type, handler, false); } else if (element.detachEvent) { element.detachEvent("on" + type, handler); } else { element["on" + type] = null; } }, // Get the event target getTarget: function(event) { return event.target || event.srcElement; }, // obtain event References to objects , Get all the information about the event , Make sure you can use event getEvent: function(event) { return event || window.event; }, // Stop the incident ( It's mainly the bubbling of events , because IE Event capture is not supported ) stopPropagation: function(event) { if (event.stopPropagation) { event.stopPropagation(); } else { event.cancelBubble = true; } }, // Cancel the default behavior of the event preventDefault: function(event) { if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } } };
Functional programming ( Commonly abbreviated as FP) By writing pure functions , Avoid sharing state 、 Variable data 、 side effect To build software . Digital programming is declarative It's not imperative Of , The state of an application flows through pure functions . Contrast with object-oriented programming , The state of an application in an object-oriented system is usually shared and coexisted with the methods in the object .
Functional programming is a programming paradigm , This means that it is based on some basic definition principles ( As listed above ) Thinking about the way of software construction . Of course , Other examples of programming paradigms include object-oriented programming and process programming .
Functional code is often simpler than imperative or object-oriented code , More predictable , Easier to test - But if you're not familiar with it and the common patterns associated with it , Functional code may also look more cluttered , also Relevant literature is not easy for new people to understand .
Higher order functions are only functions that take functions as parameters or return values .
{ return callback(param); }
stay JavaScript in , Functions not only have all the traditional ways of using functions ( Declaration and call ), And it can be done like a simple value :
var func = function(){}
)、function func(x,callback){callback();}
)、function(){return function(){}}
), Such a function is also called a first order function (First-class Function
). More Than This ,JavaScript The function in also functions as a constructor for a class , At the same time, it's another Function Class (instance). Such multiple identities make JavaScript The function of becomes very important .
Array.prototype.map Method
map() Method to create a new array , The result is the result returned after each element in the array invokes a supplied function .
{ // First , Check that the parameters passed are correct . if (!Array.isArray(arr) || !arr.length || typeof mapCallback !== 'function') { return []; } else { let result = []; // Every time this function is called , We will all create one result Array // Because we don't want to change the original array . for (let i = 0, len = arr.length; i < len; i++) { result.push(mapCallback(arr[i], i, arr)); // take mapCallback The result returned push To result Array } return result; } }
Array.prototype.filter
Method filter()
Method to create a new array , It contains all the elements of the test implemented by the provided function .
{ // First , Check that the parameters passed are correct . if (!Array.isArray(arr) || !arr.length || typeof filterCallback !== 'function') { return []; } else { let result = []; // Every time this function is called , We will all create one result Array // Because we don't want to change the original array . for (let i = 0, len = arr.length; i < len; i++) { // Check filterCallback Is the return value of true if (filterCallback(arr[i], i, arr)) { // If the condition is true , Array element push To result in result.push(arr[i]); } } return result; // return the result array } }
Array.prototype.reduce
Method reduce() Method to execute a reducer function ( Ascending execution ), Summarize its results into a single return value .
{ // First , Check that the parameters passed are correct . if (!Array.isArray(arr) || !arr.length || typeof reduceCallback !== 'function') { return []; } else { // If not initialValue Pass to this function , We will use the first array item as the initialValue let hasInitialValue = initialValue !== undefined; let value = hasInitialValue ? initialValue : arr[0]; 、 // If there is a delivery initialValue, Index from 1 Start , Otherwise, from 0 Start for (let i = hasInitialValue ? 1 : 0, len = arr.length; i < len; i++) { value = reduceCallback(value, arr[i], i, arr); } return value; } }
JavaScript It's always been difficult to copy , If now the interviewer asked me to write a deep copy , I might just be able to write a basic version of . So before I wrote this, I read the blog posts written by all kinds of big men in my favorites . You can see the link I posted below , Here's just a brief summary .
The implementation of shallow copy :
...
:a = { name: "Jake", flag: { title: "better day by day", time: "2020-05-31" } } let b = {...a};
The implementation of deep copy :
{ if(typeOf taret ==='object'){ let cloneTarget = Array.isArray(target) ? [] : {}; if(map.get(target)) { return target; } map.set(target, cloneTarget); for(const key in target){ cloneTarget[key] = cloneDeep(target[key], map); } return cloneTarget }else{ return target } }
mapTag = '[object Map]'; const setTag = '[object Set]'; const arrayTag = '[object Array]'; const objectTag = '[object Object]'; const argsTag = '[object Arguments]'; const boolTag = '[object Boolean]'; const dateTag = '[object Date]'; const numberTag = '[object Number]'; const stringTag = '[object String]'; const symbolTag = '[object Symbol]'; const errorTag = '[object Error]'; const regexpTag = '[object RegExp]'; const funcTag = '[object Function]'; const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag]; function forEach(array, iteratee) { let index = -1; const length = array.length; while (++index < length) { iteratee(array[index], index); } return array; } function isObject(target) { const type = typeof target; return target !== null && (type === 'object' || type === 'function'); } function getType(target) { return Object.prototype.toString.call(target); } function getInit(target) { const Ctor = target.constructor; return new Ctor(); } function cloneSymbol(targe) { return Object(Symbol.prototype.valueOf.call(targe)); } function cloneReg(targe) { const reFlags = /\w*$/; const result = new targe.constructor(targe.source, reFlags.exec(targe)); result.lastIndex = targe.lastIndex; return result; } function cloneFunction(func) { const bodyReg = /(?<={)(.|\n)+(?=})/m; const paramReg = /(?<=\().+(?=\)\s+{)/; const funcString = func.toString(); if (func.prototype) { const param = paramReg.exec(funcString); const body = bodyReg.exec(funcString); if (body) { if (param) { const paramArr = param[0].split(','); return new Function(...paramArr, body[0]); } else { return new Function(body[0]); } } else { return null; } } else { return eval(funcString); } } function cloneOtherType(targe, type) { const Ctor = targe.constructor; switch (type) { case boolTag: case numberTag: case stringTag: case errorTag: case dateTag: return new Ctor(targe); case regexpTag: return cloneReg(targe); case symbolTag: return cloneSymbol(targe); case funcTag: return cloneFunction(targe); default: return null; } } function clone(target, map = new WeakMap()) { // Clone the original type if (!isObject(target)) { return target; } // initialization const type = getType(target); let cloneTarget; if (deepTag.includes(type)) { cloneTarget = getInit(target, type); } else { return cloneOtherType(target, type); } // Prevent circular references if (map.get(target)) { return map.get(target); } map.set(target, cloneTarget); // clone set if (type === setTag) { target.forEach(value => { cloneTarget.add(clone(value, map)); }); return cloneTarget; } // clone map if (type === mapTag) { target.forEach((value, key) => { cloneTarget.set(key, clone(value, map)); }); return cloneTarget; } // Clone objects and arrays const keys = type === arrayTag ? undefined : Object.keys(target); forEach(keys || target, (value, key) => { if (keys) { key = value; } cloneTarget[key] = clone(target[key], map); }); return cloneTarget; } module.exports = { clone };
Reference article :
How to write a deep copy of an amazing interviewer
The ultimate exploration of deep copy (99% People don't know )
call Function implementation steps :
Function.prototype.myCall = function(context) { // Judge the calling object if (typeof this !== "function") { console.error("type error"); } // To obtain parameters let args = [...arguments].slice(1), result = null; // Judge context Whether to introduce , If it is not passed in, it is set to window context = context || window; // Methods that make the calling function an object context.fn = this; // Call function result = context.fn(...args); // Delete attribute delete context.fn; return result; };
apply Function implementation steps :
Function.prototype.myApply = function(context) { // Determine whether the calling object is a function if (typeof this !== "function") { throw new TypeError("Error"); } let result = null; // Judge context Whether there is , If not, it is window context = context || window; // Methods that make functions objects context.fn = this; // Calling method if (arguments[1]) { result = context.fn(...arguments[1]); } else { result = context.fn(); } // Delete attribute delete context.fn; return result; };
bind Function implementation steps :
Function.prototype.myBind = function(context) { // Determine whether the calling object is a function if (typeof this !== "function") { throw new TypeError("Error"); } // To obtain parameters var args = [...arguments].slice(1), fn = this; return function Fn() { // According to the way it is called , Pass in different binding values return fn.apply( this instanceof Fn ? this : context, args.concat(...arguments) ); }; };
Reference article :《 Handwriting call、apply And bind function 》
《JavaScript In depth call and apply Simulation Implementation of 》
function curry(fn, args) { // Get the parameter length required by the function let length = fn.length; args = args || []; return function() { let subArgs = args.slice(0); // Splicing to get all the existing parameters for (let i = 0; i < arguments.length; i++) { subArgs.push(arguments[i]); } // Determine whether the length of the parameter has met the length of the parameter required by the function if (subArgs.length >= length) { // If meet , Execute function return fn.apply(this, subArgs); } else { // If not satisfied , Recursively returns the corized function , Wait for the parameter to pass in return curry.call(this, fn, subArgs); } }; } // es6 Realization function curry(fn, ...args) { return fn.length <= args.length ? fn(...args) : curry.bind(null, fn, ...args); }
Reference article :《JavaScript Currization of thematic functions 》
This question, if you search the Nuggets , You may find answers like this :
Tell the truth , For the first time , I don't understand , I need to go through the prototype and prototype chain to understand . So I think MDN Yes new The explanation is easier to understand :
new
Operator to create an instance of a user-defined object type or a built-in object with a constructor .new
The keyword will do the following :
Now let's look at implementation :
{ this.name = name; this.color = color; this.age = age; } Dog.prototype={ getName: function() { return this.name } } var dog = new Dog(' rhubarb ', 'yellow', 3)
I believe the above code does not need to explain , We all know . Let's take a look at the last line new
Keyword code , According to the above 1,2,3,4 Step by step new
The operation behind it .
First step : Create a simple empty object
obj = {}
The second step : Link this object to another object ( Prototype chain )
obj.__proto__ = Dog.prototype
The third step : Will step 1 The newly created object serves as this
The context of
Dog.apply(obj, [' rhubarb ', 'yellow', 3])
Step four : If the function does not return an object , Then return to this
var dog = obj dog.getName() // ' rhubarb '
It should be noted that if Dog() Yes return Then return to return Value
rtnObj = {} function Dog(name, color, age) { // ... // Return an object return rtnObj } var dog = new Dog(' rhubarb ', 'yellow', 3) console.log(dog === rtnObj) // true
Next, we encapsulate the above steps into an object instantiation method , That is simulation new The operation of :
{ var obj = {}; // Gets the first parameter of the method ( And delete the first parameter ), This parameter is a constructor var Constructor = [].shift.apply(arguments); // Set the internal properties of the new object __proto__ Point to the prototype of the constructor , This allows the new object to access the properties and methods in the prototype obj.__proto__ = Constructor.prototype; // Get the return value of the constructor var ret = Constructor.apply(obj, arguments); // If the return value is an object, return that object , Otherwise, an instance object of the constructor is returned return typeof ret === "object" ? ret : obj; }
Callback function Is an executable code segment , It is passed to other code as a parameter , Its function is to call this paragraph when necessary ( Callback function ) Code .
stay JavaScript Middle function is also a kind of object , The same object can be passed as an argument to a function , So a function can also be passed as an argument to another function , This function as an argument is a callback function .
btnAdd = document.getElementById('btnAdd'); btnAdd.addEventListener('click', function clickCallback(e) { // do something useless });
In this case , We are waiting for id by btnAdd
Of the click
event , If it is clicked , execute clickCallback
function . Callback functions add functions to certain data or events .
The callback function has a fatal weakness , It's easy to write back to hell (Callback hell). Suppose that multiple events have dependencies :
(() => { console.log(1) setTimeout(() => { console.log(2) setTimeout(() => { console.log(3) },3000) },2000) },1000)
This is the typical callback hell , The above code seems to be hard to read and maintain , Once there are more incidents, it will be even more chaotic , So in es6 In the proposed Promise and async/await To solve the problem of callback to hell . Of course , The callback function has several other drawbacks , For example, you can't use try catch Capture the error , Not directly return. Here are the next two questions , Let's look down .
Promise, It's a promise , Promise it will give you a result in a period of time . In terms of programming Promise Is a solution to asynchronous programming . Here is Promise stay MDN Description of :
Promise Object is a proxy object ( Agent a value ), The value of being represented is Promise Object creation may be unknown . It allows you to bind the corresponding processing methods for the success and failure of asynchronous operation (handlers). This allows asynchronous methods to return values like synchronous methods , But it doesn't immediately return the final execution result , It's a result that represents the future promise object .
One Promise There are several States :
Once this commitment changes from waiting state to other state, it can never change state , That is to say, once the state becomes fulfilled/rejected after , Can't change again . Maybe we don't understand the concept Promise, Let's take a simple chestnut ;
If I had a girlfriend , Next Monday is her birthday , I promised her a surprise for her birthday , So from now on, this commitment will be in the waiting state , Waiting for next Monday , Then the state changes . If I give my girlfriend a surprise next Monday , Then the state of the commitment will be pending Switch to a fulfilled, It means that the promise has been fulfilled successfully , Once that happens , There would be no more results , That is, the state is not going to change ; On the contrary, if I work overtime because I am too busy , Forget about it , The promised surprise didn't materialize , The state will be from pending Switch to a rejected, Time can't be reversed , So the state can no longer change .
The last one we said Promise Can solve the problem of callback to hell , you 're right ,pending State of Promise Object will trigger fulfilled/rejected state , Once the status changes ,Promise Object's then Method will be called ; Otherwise it will trigger catch. Let's rewrite the previous code calling back to hell :
Promise((resolve,reject) => { setTimeout(() => { console.log(1) resolve() },1000) }).then((res) => { setTimeout(() => { console.log(2) },2000) }).then((res) => { setTimeout(() => { console.log(3) },3000) }).catch((err) => { console.log(err) })
Actually Promise There are also some shortcomings , For example, it can't be cancelled Promise, Errors need to be captured by callback functions .
promise Handwritten implementation , Interview is enough :
{ let self=this; self.status="pending" // Define the initial state before the state changes self.value=undefined;// Define status as resolved The state of being self.reason=undefined;// Define status as rejected The state of being function resolve(value){ // Two ==="pending", Ensures that the change of state is irreversible if(self.status==="pending"){ self.value=value; self.status="resolved"; } } function reject(reason){ // Two ==="pending", Ensures that the change of state is irreversible if(self.status==="pending"){ self.reason=reason; self.status="rejected"; } } // Capture structural anomalies try{ constructor(resolve,reject); }catch(e){ reject(e); } } // Defines the chain call then Method myPromise.prototype.then=function(onFullfilled,onRejected){ let self=this; switch(self.status){ case "resolved": onFullfilled(self.value); break; case "rejected": onRejected(self.reason); break; default: } }
About Promise There are other things , such as Promise.all()、Promise.race() The use of etc , Because of the space, we don't do it anymore , For a deeper understanding, please see the following article .
Related information :
「 hardcore JS」 Learn more about asynchronous solutions
【 translate 】Promises/A+ standard
Iterator
What is it? , What's the role ?Iterator
It's understanding the first 61 The prerequisite knowledge of article , Maybe it's me IQ Not enough ?,Iterator and Generator
After watching it many times, I still know nothing about it , Even if I understood , After a while, I forgot everything ...
Iterator( iterator ) It's an interface , It can also be said to be a norm . Provide unified access mechanism for different data structures . Any data structure only needs to be deployed Iterator Interface , You can complete the traversal operation ( That is, all members of the data structure are processed in turn ).
Iterator grammar :
obj = { [Symbol.iterator]:function(){} }
[Symbol.iterator]
Attribute names are written in a fixed way , As long as the object that owns the property , We can traverse it in the way of iterators .
Iterator traversal method is to first get an iterator pointer , Initially, the pointer points before the first data , Then by calling next Method , Change the direction of the pointer , Let it point to the next piece of data Every time next Will return an object , The object has two properties
Iterator There are three functions of :
Ergodic process :
Every time you call next Method , Will return information about the current member of the data structure . say concretely , Is to return a containing value and done Objects with two properties . among ,value Property is the value of the current member ,done Property is a Boolean value , Indicates whether the traversal ends .
arr = [{num:1},2,3] let it = arr[Symbol.iterator]() // Get the iterator in the array console.log(it.next()) // { value: Object { num: 1 }, done: false } console.log(it.next()) // { value: 2, done: false } console.log(it.next()) // { value: 3, done: false } console.log(it.next()) // { value: undefined, done: true }
Generator
What is a function , What's the role ?Generator Function can be said to be Iterator Specific implementation of the interface .Generator The biggest feature is that it can control the execution of functions .
{ let y = 2 * (yield (x + 1)) let z = yield (y / 3) return (x + y + z) } let it = foo(5) console.log(it.next()) // => {value: 6, done: false} console.log(it.next(12)) // => {value: 8, done: false} console.log(it.next(13)) // => {value: 42, done: true}
The above example is a Generator function , Let's analyze the execution process :
First Generator When a function is called, it returns an iterator
When executing the first time next when , The conference was ignored , And the function pauses in yield (x + 1) It's about , So back 5 + 1 = 6
When executing the second next when , The parameter passed in is equal to the previous one yield The return value of , If you don't pass it on ,yield Never return undefined. here let y = 2 * 12, So the second one yield be equal to 2 * 12 / 3 = 8
When executing the third time next when , The parameters passed in are passed to z, therefore z = 13, x = 5, y = 24, The sum is equal to 42
Generator
Functions are rarely seen , In fact, it has something to do with him , And they usually cooperate with co Library to use . Of course , We can go through Generator
Function to solve the problem of callback hell .
async/await
And how it works , What are the advantages and disadvantages ?async/await
It is based on Promise A new way to write asynchronous or non blocking code , It is generally believed that JS The ultimate and most elegant solution to asynchronous operations . be relative to Promise And callback , It is more readable and concise . After all, it's been then() I'm upset .
async
Asynchronous means , and await
yes async wait
Abbreviation , Asynchronous waiting .
So it's easy to understand semantically async Used to declare a function It's asynchronous , and await Used to wait for an asynchronous method execution to complete .
A function if you add async , Then the function will return a Promise
async function test() { return "1" } console.log(test()) // -> Promise {<resolved>: "1"}
You can see that the output is a Promise object . therefore ,async The function returns a Promise object , If in async Direct in function return A direct measure ,async I will measure this directly through PromIse.resolve()
Encapsulated into Promise Object returns .
Compared with Promise
,async/await
Can handle... Better then chain
{ return new Promise(resolve => { setTimeout(() => resolve(n + 200), n); }); } function step1(n) { console.log(`step1 with ${n}`); return takeLongTime(n); } function step2(n) { console.log(`step2 with ${n}`); return takeLongTime(n); } function step3(n) { console.log(`step3 with ${n}`); return takeLongTime(n); }
Now we use Promise
and async/await
To achieve the three steps of processing .
Use Promise
{ console.time("doIt"); const time1 = 300; step1(time1) .then(time2 => step2(time2)) .then(time3 => step3(time3)) .then(result => { console.log(`result is ${result}`); }); } doIt(); // step1 with 300 // step2 with 500 // step3 with 700 // result is 900
Use async/await
async function doIt() { console.time("doIt"); const time1 = 300; const time2 = await step1(time1); const time3 = await step2(time2); const result = await step3(time3); console.log(`result is ${result}`); } doIt();
The result is the same as before Promise The implementation is the same , But the code doesn't look much clearer , Elegant and neat , It's almost like synchronous code .
await Keywords can only be found in async function Use in . In any non async function Used in await Keywords throw errors .await Keyword waits for the right expression before executing the next line of code ( It could be a Promise) return .
Advantages and disadvantages :
async/await
The advantage is to deal with then The call chain of , Be able to write code more clearly and accurately , And it also gracefully solves the callback hell problem . Of course, there are some disadvantages , because await Transform asynchronous code into synchronous code , If more than one asynchronous code is used without dependency await Will lead to performance degradation .
Reference article :
「 hardcore JS」 Learn more about asynchronous solutions
above 21~25 The rule is JavaScript The main asynchronous solution in , There are difficulties , It needs to be studied and practiced .
instanceof Can correctly judge the type of object , Because the internal mechanism is to determine whether the type can be found in the prototype chain of the object prototype.
Realization instanceof:
First get the prototype of the type
And then get the prototype of the object
And then we loop through to determine whether the prototype of the object is equal to the prototype of the type , Until the object prototype is null, Because the prototype chain is ultimately null
{ let prototype = right.prototype left = left.__proto__ while (true) { if (left === null || left === undefined) return false if (prototype === left) return true left = left.__proto__ } }
Function anti shake When an event is triggered n Seconds before the callback , If in this n The second event is triggered again , Then the time will be counted again . This can be used on some click request events , Avoid sending multiple requests to the back end because of the user's multiple clicks .
Function throttling It means to set a unit time , In this unit time , There can only be a callback function that triggers an event once , If an event is triggered multiple times in the same unit time , Only once can it work . Throttling can be used in scroll Function event monitoring , Reduce the frequency of event calls through event throttling .
function debounce(fn, wait) { var timer = null; return function() { var context = this, args = arguments; // If there is a timer at this point , Then cancel the previous timer and record the time again if (timer) { clearTimeout(timer); timer = null; } // Set the timer , Causes the event interval to be executed after the specified event timer = setTimeout(() => { fn.apply(context, args); }, wait); }; } // The realization of function throttling ; function throttle(fn, delay) { var preTime = Date.now(); return function() { var context = this, args = arguments, nowTime = Date.now(); // If the interval between two times exceeds the specified time , Then execute the function . if (nowTime - preTime >= delay) { preTime = Date.now(); return fn.apply(context, args); } }; }
For details, please refer to :
《 Easy to understand JS Function throttling and function buffeting 》
《JavaScript Event throttling and event buffeting 》
《JS Anti shake and throttling 》
Design patterns are a set of things that are used repeatedly 、 Most people know that 、 Catalogued 、 Summary of code design experience . Design patterns are used to reuse code 、 Make code easier to understand 、 Ensure code reliability . without doubt , Design patterns win more than others and systems , Design patterns make coding really Engineering , Design patterns are the foundation of software engineering , It's like bricks and stones in a building .
Appearance pattern is one of the most common design patterns , It provides a unified high-level interface for a group of interfaces in the subsystem , Make the subsystem easier to use . In short, the appearance design pattern is to abstract the complex logic in multiple subsystems , To provide a more unified 、 More concise 、 Easier to use API. Many of the frameworks and libraries we use basically follow the design pattern , such as JQuery Just take the complex primordial DOM Operations are abstracted and encapsulated , And eliminate the compatibility problem between browsers , This provides a more advanced and easy to use version . In fact, in our daily work, we often use appearance pattern for development , It's just that we don't know it .
Compatible with browser event binding
addMyEvent = function (el, ev, fn) { if (el.addEventListener) { el.addEventListener(ev, fn, false) } else if (el.attachEvent) { el.attachEvent('on' + ev, fn) } else { el['on' + ev] = fn } };
Encapsulation interface
myEvent = { // ... stop: e => { e.stopPropagation(); e.preventDefault(); } };
scene
advantage
shortcoming
Is to provide a substitute or a place holder for an object , In order to control access to it
“ Suppose that A Receive flowers when you are in a good mood , Xiao Ming's chances of success are
60%, And when A Get flowers when you're in a bad mood , The success rate of Xiaoming's confession is infinitely close to 0. Xiao Ming and A I just met for two days , It's impossible to tell A When are you in a good mood . If you give flowers out of time A, flowers It's very likely to be thrown away , Xiao Ming ate this bunch of flowers 7 In exchange for instant noodles . however A Friend, B But I know A, So Xiao Ming just gave the flowers to B,B Will listen A The mood change of , Then choose Choose A Hand over the flowers to when you are in a good mood A, The code is as follows :
Flower = function() {} let xiaoming = { sendFlower: function(target) { let flower = new Flower() target.receiveFlower(flower) } } let B = { receiveFlower: function(flower) { A.listenGoodMood(function() { A.receiveFlower(flower) }) } } let A = { receiveFlower: function(flower) { console.log(' Get the flowers '+ flower) }, listenGoodMood: function(fn) { setTimeout(function() { fn() }, 1000) } } xiaoming.sendFlower(B)
scene
<li>1</li> <li>2</li> <li>3</li> </ul> <script> let ul = document.querySelector('#ul'); ul.addEventListener('click', event => { console.log(event.target); }); </script>
advantage
shortcoming
The factory pattern defines an interface for creating objects , This interface is determined by subclasses which class to instantiate . This pattern delays the instantiation of a class to subclasses . Subclasses can override interface methods to specify their own object types when they are created .
{ constructor(name) { this.name = name } init() { console.log('init') } fun() { console.log('fun') } } class Factory { create(name) { return new Product(name) } } // use let factory = new Factory() let p = factory.create('p1') p.init() p.fun()
scene
advantage
shortcoming
When not to
seeing the name of a thing one thinks of its function , In singleton mode Class The maximum number of instances of is 1. When you need an object to perform certain tasks throughout the system , The singleton pattern comes in handy . In addition, the use of singleton mode should be avoided in other scenarios , Because singleton mode introduces global state , A healthy system should avoid introducing too many global states .
To implement the singleton pattern, we need to solve the following problems :
We usually solve the above problems by implementing the following two points :
Javascript The singleton pattern can be implemented in the following ways :
const FooServiceSingleton = (function () { // Hidden Class Constructor for function FooService() {} // Uninitialized singleton object let fooService; return { // establish / Function to get singleton object getInstance: function () { if (!fooService) { fooService = new FooService(); } return fooService; } } })();
The key points are :
getInstance()
For one Closure , Use closures to save singleton objects in the local scope and return .We can verify that the singleton object was created successfully :
fooService1 = FooServiceSingleton.getInstance(); const fooService2 = FooServiceSingleton.getInstance(); console.log(fooService1 === fooService2); // true
Scene example
advantage
shortcoming
The simple description of the strategy pattern is : The object has some behavior , But in different scenarios , There are different implementation algorithms for this behavior . Encapsulate them one by one , And make them interchangeable
<head> <title> The strategy pattern - Checklists </title> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> </head> <body> <form id = "registerForm" method="post" action="http://xxxx.com/api/register"> user name :<input type="text" name="userName"> password :<input type="text" name="password"> Phone number :<input type="text" name="phoneNumber"> <button type="submit"> Submit </button> </form> <script type="text/javascript"> // Policy object const strategies = { isNoEmpty: function (value, errorMsg) { if (value === '') { return errorMsg; } }, isNoSpace: function (value, errorMsg) { if (value.trim() === '') { return errorMsg; } }, minLength: function (value, length, errorMsg) { if (value.trim().length < length) { return errorMsg; } }, maxLength: function (value, length, errorMsg) { if (value.length > length) { return errorMsg; } }, isMobile: function (value, errorMsg) { if (!/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[7]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.test(value)) { return errorMsg; } } } // Validation class class Validator { constructor() { this.cache = [] } add(dom, rules) { for(let i = 0, rule; rule = rules[i++];) { let strategyAry = rule.strategy.split(':') let errorMsg = rule.errorMsg this.cache.push(() => { let strategy = strategyAry.shift() strategyAry.unshift(dom.value) strategyAry.push(errorMsg) return strategies[strategy].apply(dom, strategyAry) }) } } start() { for(let i = 0, validatorFunc; validatorFunc = this.cache[i++];) { let errorMsg = validatorFunc() if (errorMsg) { return errorMsg } } } } // Calling code let registerForm = document.getElementById('registerForm') let validataFunc = function() { let validator = new Validator() validator.add(registerForm.userName, [{ strategy: 'isNoEmpty', errorMsg: ' The user name cannot be empty ' }, { strategy: 'isNoSpace', errorMsg: ' Names with white space characters are not allowed ' }, { strategy: 'minLength:2', errorMsg: ' User name length cannot be less than 2 position ' }]) validator.add(registerForm.password, [ { strategy: 'minLength:6', errorMsg: ' Password length cannot be less than 6 position ' }]) validator.add(registerForm.phoneNumber, [{ strategy: 'isMobile', errorMsg: ' Please enter the correct mobile phone number format ' }]) return validator.start() } registerForm.onsubmit = function() { let errorMsg = validataFunc() if (errorMsg) { alert(errorMsg) return false } } </script> </body> </html>
Scene example
advantage
shortcoming
If you see this ,ES6 Iterators in Iterator I believe you still have some impression , The above first 60 The article has already made a brief introduction . The iterator pattern simply provides a method order for aggregating the elements of an object , Without exposing the internal representation of the object .
The iterator pattern solves the following problems :
An iterator usually needs to implement the following interfaces :
by Javascript An iterator can be written like this :
item = [1, 'red', false, 3.14]; function Iterator(items) { this.items = items; this.index = 0; } Iterator.prototype = { hasNext: function () { return this.index < this.items.length; }, next: function () { return this.items[this.index++]; } }
Verify that the iterator works :
iterator = new Iterator(item); while(iterator.hasNext()){ console.log(iterator.next()); } // Output :1, red, false, 3.14
ES6 Provides a simpler iteration loop syntax for...of, The premise of using this syntax is that the operation object needs to implement Iterative protocol (The iterable protocol), In short, the object has a Key by Symbol.iterator Methods , This method returns a iterator object .
For example, we implement a Range Class is used to iterate over a range of numbers :
{ return { [Symbol.iterator]: function () { return { next() { if (start < end) { return { value: start++, done: false }; } return { done: true, value: end }; } } } } }
Check it out :
(num of Range(1, 5)) { console.log(num); } // Output :1, 2, 3, 4
Observer mode also called Release - A subscription model (Publish/Subscribe Pattern), It's a design pattern that we're often exposed to , Applications in daily life can also be found everywhere , For example, you subscribe to a blogger's Channel , When there's a content update, you get a push ; And such as JavaScript Event subscription response mechanism in . The idea of the observer pattern can be described in one sentence as : The object of observation (subject) Maintain a group of observers (observer), When the state of the observed object changes , Notify the observer of these changes by calling one of the observer's methods .
In observer mode Subject Objects generally need to implement the following API:
use JavaScript Manually implement observer mode :
function Subject() { this.observers = []; } Subject.prototype = { // subscribe subscribe: function (observer) { this.observers.push(observer); }, // Unsubscribe unsubscribe: function (observerToRemove) { this.observers = this.observers.filter(observer => { return observer !== observerToRemove; }) }, // Events trigger fire: function () { this.observers.forEach(observer => { observer.call(); }); } }
Verify that the subscription was successful :
subject = new Subject(); function observer1() { console.log('Observer 1 Firing!'); } function observer2() { console.log('Observer 2 Firing!'); } subject.subscribe(observer1); subject.subscribe(observer2); subject.fire(); // Output : Observer 1 Firing! Observer 2 Firing!
Verify that unsubscribe was successful :
subject.unsubscribe(observer2); subject.fire(); Observer 1 Firing!
scene
.body.addEventListener('click', function() { console.log('hello world!'); }); document.body.click()
advantage
shortcoming
In the mediator model , Intermediary (Mediator) It encapsulates a series of ways in which objects interact , So that these objects don't have to interact directly , It's about mediators coordinating their interactions , So that they can be loosely coupled . When the action between certain objects changes , Does not immediately affect the role of some other objects , Make sure that these functions can be changed independently of each other .
There are some similarities between the mediator model and the observer model , It's all one to many relationships , It's all centralized communication , The difference is that the mediator pattern deals with interactions between peers , And the observer model is processing Observer and Subject Interaction between . The intermediary model is somewhat like a marriage intermediary , The blind date can't communicate directly at first , It's about screening matches through intermediaries and deciding who to meet with .
scene
goods = { // Mobile phone inventory 'red|32G': 3, 'red|64G': 1, 'blue|32G': 7, 'blue|32G': 6, }; // Intermediary var mediator = (function() { var colorSelect = document.getElementById('colorSelect'); var memorySelect = document.getElementById('memorySelect'); var numSelect = document.getElementById('numSelect'); return { changed: function(obj) { switch(obj){ case colorSelect: //TODO break; case memorySelect: //TODO break; case numSelect: //TODO break; } } } })(); colorSelect.onchange = function() { mediator.changed(this); }; memorySelect.onchange = function() { mediator.changed(this); }; numSelect.onchange = function() { mediator.changed(this); };
Member class chat room :
{ this.name = name; this.chatroom = null; } Member.prototype = { // Send a message send: function (message, toMember) { this.chatroom.send(message, this, toMember); }, // receive messages receive: function (message, fromMember) { console.log(`${fromMember.name} to ${this.name}: ${message}`); } }
Chat room class :
{ this.members = {}; } Chatroom.prototype = { // Add members addMember: function (member) { this.members[member.name] = member; member.chatroom = this; }, // Send a message send: function (message, fromMember, toMember) { toMember.receive(message, fromMember); } }
Test it :
chatroom = new Chatroom(); const bruce = new Member('bruce'); const frank = new Member('frank'); chatroom.addMember(bruce); chatroom.addMember(frank); bruce.send('Hey frank', frank); // Output :bruce to frank: hello frank
advantage
shortcoming
Visitor mode It is a design pattern that separates algorithm from object structure , In layman's terms : Visitor mode allows us to add new logic to an object without changing its structure , The added logic is stored in a separate visitor object . Visitor patterns are often used to expand third-party libraries and tools .
class Visitor { constructor() {} visitConcreteElement(ConcreteElement) { ConcreteElement.operation() } } // Element class class ConcreteElement{ constructor() { } operation() { console.log("ConcreteElement.operation invoked"); } accept(visitor) { visitor.visitConcreteElement(this) } } // client let visitor = new Visitor() let element = new ConcreteElement() elementA.accept(visitor)
The implementation of the visitor pattern has the following elements :
visit()
Method accept()
Method Receiving Object
Receving Object
Receive one Visitor, And by calling Visitor
Of visit()
Provide access to Receiving Object
The power of data The simple code implementation is as follows :
Receiving : function Employee(name, salary) { this.name = name; this.salary = salary; } Employee.prototype = { getSalary: function () { return this.salary; }, setSalary: function (salary) { this.salary = salary; }, accept: function (visitor) { visitor.visit(this); } } Visitor Object: function Visitor() { } Visitor.prototype = { visit: function (employee) { employee.setSalary(employee.getSalary() * 2); } }
Check it out :
employee = new Employee('bruce', 1000); const visitor = new Visitor(); employee.accept(visitor); console.log(employee.getSalary());// Output :2000
scene
advantage
shortcoming
above 66 This article is the summary of the recent resumption , On the whole, it's in the order from shallow to deep , A small part of the content is not original , I've posted a link at the end of each reference , Here, I would like to thank you for your blogs , It helped me a lot ~
The front end is a hodgepodge , Various frameworks emerge in endlessly , But everything changes JS, Pragmatic basis is fundamental , If you think this article will help you , Please give me a favor ~
This article is from WeChat official account. - The sea, here I come (bubuzouweb) , author :Jake Zhang
The source and reprint of the original text are detailed in the text , If there is any infringement , Please contact the [email protected] Delete .
Original publication time : 2021-02-05
Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .