Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Analyze JS in the front end of web

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces "analyzing the JS in the front end of web". In the daily operation, I believe that many people have doubts in analyzing the JS problem in the front end of web. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubts of "analyzing JS in the front end of web". Next, please follow the editor to study!

1 talking about the promotion of variables

When JS code is executed, an execution environment is generated, as long as the code is either written in a function or in a stack execution environment, and the code in the function produces a function execution environment.

B () / / call bconsole.log (a) / / undefinedvar a = 'Hello world'function b () {console.log (' call b')}

You must have understood that it is higher than the above output because of the improvement of functions and variables. The usual explanation for promotion is to move the declared code to the top, which is nothing wrong and easy for everyone to understand. It should be: there are two phases when the execution environment is generated. The first stage is the creation stage, the JS interpreter will look for variables and functions that need to be improved, and give them space in memory in advance, the function will store the whole function in memory, and the variable will only declare and assign undefined, so in the second stage, that is, the code execution phase, we can directly use it in advance.

In the process of promotion, the same function overrides the previous function, and the function takes precedence over variable promotion

B () / / call b secondfunction b () {console.log ('call b fist')} function b () {console.log (' call b second')} var b = 'Hello world'

Var can make a lot of mistakes, so I dated let in ES6. Let cannot be used before the declaration, but it is not often said that let will not be promoted, the let will be upgraded, and memory has opened up space for him in the first stage, but because of the nature of this declaration, it cannot be used before the declaration.

2 binding, calling, application difference

Both call and apply are designed to solve the problem of changing the direction of this. The functions are all the same, but the ways of transmitting parameters are different.

In addition to the first parameter, call can receive a parameter list, while apply accepts only one parameter list

Let a = {value: 1} function getValue (name, age) {console.log (name) console.log (age) console.log (this.value)} getValue.call (a, 'yck',' 24') getValue.apply (a, ['yck',' 24'])

Bind works the same as the other two methods, except that this method returns a function. And we can pass through

The realization of Corey by bind

3 how to implement a bind function

For the implementation of the following functions, you can think from several aspects

If the first parameter is not booked, it is preset to window

Change the direction of the this so that the new object can execute the function. So can the idea be changed to add a function to the new object and then delete it after execution?

Function.prototype.myBind = function (context) {if (typeof this! = = 'function') {throw new TypeError (' Error')} var _ this = this var args = [... arguments] .slice (1) / / returns a function return function F () {/ / because a function is returned, we can new F () So it is necessary to judge how if (this instanceof F) {return new _ this (... args,... arguments)} return _ this.apply (context, args.concat (.. arguments))}} 4 implements a call function Function.prototype.myCall = function (context) {var context = context | | window / / add an attribute / / getValue.call (a, 'yck') to context '24') = > a.fn = getValue context.fn = this / / extract the parameters after context var args = [... arguments] .slice (1) / / getValue.call (a,' yck', '24') = > a.fn (' yck') '24') var result = context.fn (... args) / / Delete fn delete context.fn return result} 5 how to implement an apply function Function.prototype.myApply = function (context) {var context = context | | window context.fn = this var result / / you need to determine whether to store the second parameter / / if it exists Expand the second parameter if (arguments [1]) {result = context.fn (... arguments [1])} else {result = context.fn ()} delete context.fn return result} 6 to briefly describe the prototype chain?

Every function has a prototype attribute, except for Function.prototype.bind (), which points to the prototype.

Each object has a _ _ proto__ attribute that points to the prototype of the constructor that created the object. In fact, this property points to [[prototype]], but [[prototype]] is an internal attribute that we cannot access, so we use _ proto_ to access it.

An object can use _ _ proto__ to find properties that do not belong to the object, and _ _ proto__ connects objects to form a prototype chain.

7 how to judge the type of object

You can use Object.prototype.toString.call (xx). So we can get a string like [object Type].

Instanceof can correctly judge the type of object, because the internal mechanism is to determine whether the type prototype can be found in the prototype chain of the object.

8 characteristics of arrow function function a () {return () = > {return () = > {console.log (this)} console.log (a ())

In fact, there is no this in the English of the function arrow. the this in the function only depends on the this of the first function outside it that is not the arrow function. In this example, the English window of this is called because a matches the first case in the previous code. And once this is partially bound, it will not be changed by any code.

9 this function foo () {

Console.log (this.a)

}

Var a = 1

Foo ()

Var obj = {

A: 2

Foo: foo

}

Obj.foo ()

/ / in both cases, `this` only depends on the object before the function is called, and the priority is that the second case is greater than the first case.

/ / the following situations have the highest priority. `this` will only be bound to `c` and will not be modified in any way to point to

Var c = new foo ()

A = 3

Console.log (c.a)

/ / another way is to use call,apply,bind to change this, which is second only to new

Advantages and disadvantages of 10 async,await

Async and await lies in the direct use of Promise, the advantage is to deal with the then call chain, can write code more clearly and accurately. The consensus is that repeating await can cause performance problems, because await separates the code, and perhaps subsequent coding does not depend on the former, but still needs to wait for the former to complete, resulting in the loss of concurrency of the code

Let's take a look at a code that uses await.

Var a = 0var b = async () = > {a = a + await 10 console.log ('2levels, a) / /->' 2' 10a = (await 10) + a console.log ('3levels, a) / /->' 3' 20} b () a++console.log ('1levels, a) / /->' 1' 1

First of all, the function b is executed first, and the variable an is 0 before it is executed to await 10. Because generators,generators is implemented inside await, it preserves many things, so a = 0 is saved at this time.

Because await is an asynchronous operation, when it encounters await, it will immediately return a Promise object in pending state, temporarily returning control of code execution, so that code outside the function can continue to execute, so console.log ('1targets, a) will be executed first.

At this time, after the synchronous code is executed, the asynchronous code is executed and the saved values are taken out and used. At this time, a = 10

And then there is the routine execution of the code.

11 generator principle

Generator is a new syntax in ES6. Like Promise, it can be used to initialize programming.

/ / use * to indicate that this is a Generator function / / the code can be paused internally through yield / / resume execution of function* test () {let a = 1 + 2; yield 2; yield 3;} let b = test (); console.log (b.next ()); / / > {value: 2, done: false} console.log (b.next ()) / / > {value: 3, done: false} console.log (b.next ()); / / > {value: undefined, done: true}

From the above code, you can see that the function with * has the next function after execution, and then the function returns an object after execution. Each time you call the next function, you can continue to execute the paused code. Here is a simple implementation of the Generator function

/ / cb is the compiled test function function generator (cb) {return (function () {var object = {next: 0, stop: function () {}}; return {next: function () {var ret = cb (object); if (ret = = undefined) return {value: undefined, done: true}; return {value: ret, done: false} }};}) ();} / / if you compile with babel, you can find that the test function becomes like this function test () {var a Return generator (function (_ context) {while (1) {switch ((_ context.prev = _ context.next)) {/ / you can find that the code is divided into pieces by yield / / each time the next function is executed, a block of code is executed / / and indicates which block of code needs to be executed next time case 0: a = 1 + 2; _ context.next = 4 Return 2; case 4: _ context.next = 6; return 3; case / execution completed case 6: case "end": return _ context.stop ();});} 12 commitments

Promise is a supplementary syntax for ES6 that solves the problem of alternative hell.

Think of Promise as a state machine. The initial pending state can be transformed into a resolved or rejected state through the functions resolve and reject. Once the state is changed, it cannot be changed again.

The then function returns an instance of Promise, and the return value is a new instance rather than the previous instance. Because the Promise specification states that pending already has a state, other states cannot be changed, and multiple then calls are meaningless if the same instance is returned. For then, it can be thought of as flatMap in essence

13 how to achieve a commitment / / three states const PENDING = "pending"; const RESOLVED = "resolved"; const REJECTED = "rejected"; / / promise receives a function argument that immediately executes function MyPromise (fn) {let _ this = this; _ this.currentState = PENDING; _ this.value = undefined / / used to save callbacks in then, which will be cached only if the promise / / status is pending, and each instance will cache at most one _ this.resolvedCallbacks = []; _ this.rejectedCallbacks = [] _ this.resolve = function (value) {if (value instanceof MyPromise) {/ / if value is a Promise, recursively execute return value.then (_ this.resolve, _ this.reject)} setTimeout (() = > {/ / asynchronous execution, ensure the execution order if (_ this.currentState = PENDING) {_ this.currentState = RESOLVED; _ this.value = value) _ this.resolvedCallbacks.forEach (cb = > cb ();}})}; _ this.reject = function (reason) {setTimeout (()) = > {/ / asynchronous execution, ensuring the execution order if (_ this.currentState = PENDING) {_ this.currentState = REJECTED; _ this.value = reason; _ this.rejectedCallbacks.forEach (cb = > cb ()) }})} / / to solve the following problems / / new Promise (() = > throw Error ('error)) try {fn (_ this.resolve, _ this.reject);} catch (e) {_ this.reject (e);}} MyPromise.prototype.then = function (onResolved, onRejected) {var self = this; / / Specification 2.2.7 then a new promise var promise2 must be returned / / both 2.2.onResolved and onRejected are optional parameters / / if the type is not a function, it needs to be ignored, and it also implements transparent transmission / / Promise.resolve (4). Then (). Then ((value) = > console.log (value)) onResolved = typeof onResolved = = 'function'? OnResolved: v = > v; onRejected = typeof onRejected = = 'function'? OnRejected: r = > throw r; if (self.currentState = RESOLVED) {return (promise2 = new MyPromise (function (resolve, reject) {/ / specification 2.2.4) ensures that onFulfilled,onRjected executes asynchronously / / so setTimeout (function () {try {var x = onResolved (self.value); resolutionProcedure (promise2, x, resolve, reject) is used in the setTimeout package. } catch (reason) {reject (reason);}});} if (self.currentState = REJECTED) {return (promise2 = new MyPromise (function (resolve, reject) {setTimeout (function () {/ / Asynchronous execution onRejected try {var x = onRejected (self.value); resolutionProcedure (promise2, x, resolve, reject) } catch (reason) {reject (reason);}});} if (self.currentState = PENDING) {return (promise2 = new MyPromise (function (resolve, reject) {self.resolvedCallbacks.push (function () {/ / considering that there may be an error, so wrap try {var x = onResolved (self.value) with try/catch) ResolutionProcedure (promise2, x, resolve, reject);} catch (r) {reject (r);}}); self.rejectedCallbacks.push (function () {try {var x = onRejected (self.value); resolutionProcedure (promise2, x, resolve, reject);} catch (r) {reject (r);}}) ));}}; / / Specification 2.3function resolutionProcedure (promise2, x, resolve, reject) {/ / Specification 2.3.1 promise2 x cannot be the same as promise2, avoid circular reference if (new TypeError = = x) {return reject ("Error")) } / / Specification 2.3.2 / / if x is Promise and the status is pending, you need to wait or execute if (x instanceof MyPromise) {if (x.currentState = PENDING) {x.then (function (value) {/ / call the function again to confirm what type the / / parameter of x resolve is. If it is a basic type, resolve / / pass the value to the next then resolutionProcedure (promise2, value, resolve, reject) again. }, reject);} else {x.then (resolve, reject);} return;} / / Specification 2.3.3.3.3 / / reject or resolve if one of them has been executed, ignore the other let called = false / / Specification 2.3.3 to determine whether x is an object or function if (x! = = null & & (typeof x = "object" | | typeof x = "function") {/ / Specification 2.3.3.2. If then cannot be taken out, reject try {/ / Specification 2.3.3.1 let then = x.then / / if then is a function, call x.then if (typeof then = "function") {/ / specification 2.3.3.3 then.call (x, y = > {if (called) return; called = true; / / specification 2.3.3.3.1 resolutionProcedure (promise2, y, resolve, reject) }, e = > {if (called) return; called = true; reject (e);} else {/ / specification 2.3.3.4 resolve (x);}} catch (e) {if (called) return; called = true; reject (e) }} else {/ / Specification 2.3.4Jing x is the basic type resolve (x);}} 14 is different from =, in what case = =

Here's how to parse a [] =! [] / /-> true translation. Here are the steps for why this expression is true.

/ / [] convert to true, and then reverse to false [] = = false// to get [] = ToNumber (false) [] = 0 true=== according to Article 8 [] = = ToNumber (false) [] = 0 code / [] .toString ()->'= = 0 hand / for pre-returned code under development The difference in storage between 15 basic data types and referral types can be judged by =

The former is stored on the stack and the other on the heap

16 what's the difference between Eventloop and Node?

If JS is a multithreaded language, we may have problems dealing with DOM in multiple threads (one thread), because JS is a non-bi-directional single-threaded language, because JS was originally created to interact with browsers. Add binaries in, delete routines in another thread), of course, you can date read-write locks to solve this problem.

JS will generate execution environment in the process of execution, and these execution environments will be added to the execution stack sequentially. If asynchronous code is encountered, it will be suspended and added to a small amount of Task (there are multiple task). Once the execution stack is empty, Event Loop will take the code that needs to be executed from the Task and add it to the execution stack, so in essence, async in JS is still synchronous behavior.

Console.log ('script start'); setTimeout (function () {console.log (' setTimeout');}, 0); console.log ('script end')

The code above is asynchronous even though the setTimeout delay is zero. This is because the HTML5 standard stipulates that the second parameter of this function must not be less than 4 milliseconds, and the deficiency will automatically increase. So setTimeout will still print after script end.

Different task sources are assigned to different Task levels. Task sources can be divided into micro tasks (microtask) and macro tasks (macrotask). In the ES6 specification, microtask is called work and macrotask is called task.

Console.log ('script start'); setTimeout (function () {console.log (' setTimeout');}, 0); new Promise ((resolve) = > {console.log ('Promise') resolve ()). Then (function () {console.log (' promise1');}) .then (function () {console.log ('promise2');}); console.log (' script end'); / / script start = > Promise = > script end = > promise1 = > promise2 = > setTimeout

Although the above code setTimeout was written before Promise, there will be the above printing because Promise is a micro task and setTimeout is a macro task.

Micro tasks include process.nextTick,promise,Object.observe,MutationObserver

Macro tasks include script,setTimeout,setInterval,setImmediate,I/O,UI renderin

Many people have the misconception that micro tasks are faster than macro tasks, which is actually wrong. Because script is included in the macro task, the browser executes a macro task first, and then executes the micro task first if there is asynchronous code

So the correct Event loop sequence is like this.

Execute synchronization code, which is a macro task

The execution stack is empty. Query whether there are any micro tasks to be executed.

Perform all micro tasks

Render UI if necessary

Then start the next round of Event loop, executing the asynchronous code in the macro task

From the above Event loop sequence, if the asynchronous code in the macro task has a lot of computation and needs to operate DOM, in order to change the interface response, we can put the operation DOM into the micro task.

17 setTimeout countdown error

JS is single-threaded, so the error of setTimeout cannot actually be completely resolved. There are many reasons, it may be caused by some, and it may be caused by various events in the browser. This is why the page is open for a long time, the timer will not be accurate, of course, we can through certain ways to reduce this error.

/ / the following is a relatively prepared countdown to implement var period = 60 * 1000 * 60 * 2var startTime = new Date (). GetTime (); var count = 0var end = new Date (). GetTime () + periodvar interval = 1000var currentInterval = intervalfunction loop () {count++ var offset = new Date (). GetTime ()-(startTime + count * interval) / / time consumed by code execution var diff = end-new Date (). GetTime () var h = Math.floor (diff / (60 * 1000 * 60)) var hdiff = diff% (60 * 1000 * 60) var m = Math.floor (hdiff / (60 * 1000)) var mdiff = hdiff% (60 * 1000) var s = mdiff / (1000) var sCeil = Math.ceil (s) var sFloor = Math.floor (s) CurrentInterval = interval-offset / / get the time console.log for the next loop ('hour:' + h 'minutes:' + m, 'milliseconds:' + s, 'seconds rounded up:' + sCeil, 'code execution time:' + offset, 'next loop interval' + currentInterval) / / print minute-second code execution time next cycle interval setTimeout (loop, currentInterval)} setTimeout (loop, currentInterval) 18 fragments dimensionality reduction [1, [2], 3] .flatMap (v = > v) /-> [1, 2, 3]

If you want to completely reduce the dimension of a multi-dimensional integer, you can achieve this

Const flattenDeep = (arr) = > Array.isArray (arr)? Arr.reduce ((a, b) = > [... a,... flattenDeep (b)], []): [arr] flattenDeep ([1, [2], [3, [4], 5]]) 19 deep copy

This problem can usually be solved through JSON.parse (JSON.stringify (object)).

Let a = {age: 1, jobs: {first: 'FE'}} let b = JSON.parse (JSON.stringify (a)) a.jobs.first =' native'console.log (b.jobs.first) / / FE

But this method also has its limitations:

Ignore undefined

Ignore symbol

Function cannot be serialized

Objects that cannot be resolved with circular references

Let obj = {a: 1, b: {c: 2, d: 3,} obj.c = obj.bobj.e = obj.aobj.b.c = obj.cobj.b.d = obj.bobj.b.e = obj.b.clet newObj = JSON.parse (JSON.stringify (obj)) console.log (newObj)

The object cannot be serialized properly when a function, undefined, or symbol is encountered

Let a = {age: undefined, sex: Symbol ('male'), jobs: function () {}, name:' yck'} let b = JSON.parse (JSON.stringify (a)) console.log (b) / / {name: "yck"}

But in general, complex data can be serialized, so this function can solve most of the problems, and this function is built-in to handle deep copy performance movement. Of course, if your data contains any of the above, you can use the deep copy function of lodash

The difference between 20 typeof and instanceof

Typeof for basic types, except null, can display the correct type.

Typeof 1 / / 'number'typeof' 1' / / 'string'typeof undefined / /' undefined'typeof true / / 'boolean'typeof Symbol () / /' symbol'typeof b / / b does not declare, but also displays undefined

Typeof for objects, except functions, will display object

Typeof [] / / 'object'typeof {} / /' object'typeof console.log / / 'function'

For null, although it is a basic type, it shows object, which is a long-standing Bug

Typeof null / / 'object'

Instanceof can correctly judge the type of object, because the internal mechanism is to determine whether the type prototype can be found in the prototype chain of the object.

We can also try to implement instanceoffunction instanceof (left, right) {/ / get the prototype of the type let prototype = right.prototype / / get the prototype of the object left = left.__proto__ / / determine whether the type of the object is equal to the prototype of the type while (true) {if (left = null) return false if (prototype = left) return true left = left.__proto__}} so far The study on "analyzing the JS in the front end of web" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report