-
Original address: Code Output for Front End Interview Questions
-
git address: https://gitee.com/AiShiYuShiJiePingXing/lovebetterworld
Preface:
The result of code output is also a common topic in interviews. A lot of knowledge points may be involved in a piece of code, which examines the basic ability of the candidate. In front-end interviews, the problem of code output in common examinations mainly involves the following knowledge points: asynchronous programming, event loop, this pointing, scope, variable promotion, closure, prototype, inheritance, etc. These knowledge points often do not appear alone, but contain more than one knowledge point in the same code. Therefore, the author roughly classifies these issues into four categories for discussion. Instead of systematically explaining the basics here, the knowledge points of each topic and the execution of the code are described in the form of interview examples. With these examples, most of the code output problems in front-end interviews can be easily solved.
**Note:**All the examples in this article are collected from Niuke MedianJing, Internet blog, etc. If infringement occurs, please contact to delete it!
1. Asynchronous-Event Cycle
1. Code Output Results
const promise = new Promise((resolve, reject) => { console.log(1); console.log(2); }); promise.then(() => { console.log(3); }); console.log(4);
The output is as follows:
1 2 4
Promise. The then is a micro task, which will not execute until all macro tasks have been executed, and requires a change in the state within promise because there is no change in the interior and it remains in the pending state, so it does not output 3.
2. Code Output Results
const promise1 = new Promise((resolve, reject) => { console.log('promise1') resolve('resolve1') }) const promise2 = promise1.then(res => { console.log(res) }) console.log('1', promise1); console.log('2', promise2);
The output is as follows:
promise1 1 Promise{<resolved>: resolve1} 2 Promise{<pending>} resolve1
It is important to note that printing promise1 directly will print out its status values and parameters.
The code is executed as follows:
- script is a macro task that executes the code in sequence;
- First enter Promise, execute the code in the constructor, and print promise1;
- When the resolve function is encountered, the promise1 state is changed to resolved and the result is saved.
- Encountered promise1. The microtask, put it in the microtask queue;
- promise2 is a romise with a new pending state;
- Execute synchronization code 1 and print out promise 1 as resolved.
- Execute synchronization code 2 and print out promise 2 as pending.
- When the macro task is finished, look for the micro task queue and find promise1. The microtask with the status resolved executes it.
3. Code Output Results
const promise = new Promise((resolve, reject) => { console.log(1); setTimeout(() => { console.log("timerStart"); resolve("success"); console.log("timerEnd"); }, 0); console.log(2); }); promise.then((res) => { console.log(res); }); console.log(4);
The output is as follows:
1 2 4 timerStart timerEnd success
The code is executed as follows:
- Encounters the Promise constructor first, executes its contents, prints 1;
- Encountered the timer steTimeout, which is a macro task, put into the macro task queue;
- Continue down and print out 2;
- Promise is still pending at this time, so promise. The N does not execute first;
- Continue with the following synchronization tasks, print out 4;
- At this time, the micro-task queue has no tasks, and continues to perform the next round of macro tasks, steTimeout;
- First timerStart is executed, then resolve is encountered, changing the status of promise to resolved and saving the result and the previous promise. The n pushes into the microtask queue and executes timerEnd;
- Once you've finished this macro task, go ahead and perform the microtask promise.then, print out the result of resolve.
4. Code Output Results
Promise.resolve().then(() => { console.log('promise1'); const timer2 = setTimeout(() => { console.log('timer2') }, 0) }); const timer1 = setTimeout(() => { console.log('timer1') Promise.resolve().then(() => { console.log('promise2') }) }, 0) console.log('start');
The output is as follows:
start promise1 timer1 promise2 timer2
The code is executed as follows:
- First, Promise. Resolve (). The n is a microtask, joining the microtask queue
- Execute timer1, which is a macro task, joining the macro task queue
- Continue with the synchronization code below and print out the start
- This completes the first macro task and starts the microtask Promise.resolve().then, print out promise1
- When timer2 is encountered, it is a macro task and joins it to the macro task queue. There are two tasks in the macro task queue, timer1 and timer2.
- Then the first round of micro tasks is finished, and the second round of macro tasks is started. First, timer timer1 is executed and timer1 is printed.
- Encountered Promise.resolve().then, it's a microtask, joining the microtask queue
- Start executing tasks in the microtask queue and print promise2;
- Finally, execute the macro task timer2 timer, print out timer2;
5. Code Output Results
const promise = new Promise((resolve, reject) => { resolve('success1'); reject('error'); resolve('success2'); }); promise.then((res) => { console.log('then:', res); }).catch((err) => { console.log('catch:', err); })
The output is as follows:
then: success1
This topic examines how Promise's state does not change after it has changed. The start state changes from pending to resolve, indicating that it has changed to completed state, and the following two states will no longer execute, and the following catches will not catch errors.
6. Code Output Results
Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .then(console.log)
The output is as follows:
1 Promise {<fulfilled>: undefined}
Promise. The parameter of the resolve method Promise if it is an original value or an object without the then method. The resolve method returns a new Promise object with the status resolved, Promise. The parameters of the resolve method are passed to the callback function at the same time.
The argument accepted by the then method is a function, and if it does not pass a function, it actually interprets it as then(null), which causes the result of the previous Promise to pass below.
7. Code Output Results
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) }) const promise2 = promise1.then(() => { throw new Error('error!!!') }) console.log('promise1', promise1) console.log('promise2', promise2) setTimeout(() => { console.log('promise1', promise1) console.log('promise2', promise2) }, 2000)
The output is as follows:
promise1 Promise {<pending>} promise2 Promise {<pending>} Uncaught (in promise) Error: error!!! promise1 Promise {<fulfilled>: "success"} promise2 Promise {<rejected>: Error: error!!}
8. Code Output Results
Promise.resolve(1) .then(res => { console.log(res); return 2; }) .catch(err => { return 3; }) .then(res => { console.log(res); });
The output is as follows:
1 2
Promise can be called chained because each call. then or. catch returns a new promise, which implements a chain call, which does not return this like a chain call for a normal task.
The output above prints out 1 and 2 in turn because after resolve(1), the first then method is taken and not entered the catch, so the res in the second then actually gets the return value of the first then. And return 2 is packaged as resolve(2), which is printed out by the last then 2.
9. Code Output Results
Promise.resolve().then(() => { return new Error('error!!!') }).then(res => { console.log("then: ", res) }).catch(err => { console.log("catch: ", err) })
The output is as follows:
"then: " "Error: error!!!"
Returning any Non-promise value is wrapped as a promise object, so the return new Error('error!!!') here is also wrapped as a return Promise.resolve(new Error('error!!!'), so it will be caught by the then instead of catch.
10. Code Output Results
const promise = Promise.resolve().then(() => { return promise; }) promise.catch(console.err)
The output is as follows:
Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
This is actually a pit. The N or. catch cannot return a value that is promise itself, otherwise it causes an endless loop.
11. Code Output Results
Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .then(console.log)
The output is as follows:
1
Seeing this topic, many then, actually just need to remember one principle:. The N or. A catch's parameter expects a function, while a non-function is passed in and a value pass-through occurs.
Neither the first nor the second one passes in a function, a number, or an object, so a transfer occurs, passing the value of resolve(1) directly to the last one and printing out 1.
12. Code Output Results
Promise.reject('err!!!') .then((res) => { console.log('success', res) }, (err) => { console.log('error', err) }).catch(err => { console.log('catch', err) })
The output is as follows:
error err!!!
We know,. Two parameters in the then function:
- The first parameter is the function used to handle Promise success
- The second is a function that handles failures
That is to say Promise. The value of resolve ('1') will enter the successful function, Promise. The reject ('2') value enters the failed function.
In this question, the error is directly caught by the second parameter of the n, so it will not be caught by the catch. The output is: error err!!!'
But if it's like this:
Promise.resolve() .then(function success (res) { throw new Error('error!!!') }, function fail1 (err) { console.log('fail1', err) }).catch(function fail2 (err) { console.log('fail2', err) })
If an error is thrown in the first parameter of the then he will not be inactive by the second parameter but will be caught by the subsequent catch.
13. Code Output Results
Promise.resolve('1') .then(res => { console.log(res) }) .finally(() => { console.log('finally') }) Promise.resolve('2') .finally(() => { console.log('finally2') return 'I am finally2 Return value' }) .then(res => { console.log('finally2 Hinder then function', res) })
The output is as follows:
1 finally2 finally finally2 Hinder then Function 2
.finally() is rarely used. Just remember the following points:
- The.finally() method executes regardless of the final state of the Promise object
- The callback function of the.Finally() method does not accept any parameters, that is, you are in. It is not known in the finally() function whether the final state of Promise is resolved or rejected
- The default it eventually returns is the last Promise object value, but if an exception is thrown, it returns the Promise object with the exception.
- finally is essentially a special case of the then method
Error capture for.finally():
Promise.resolve('1') .finally(() => { console.log('finally1') throw new Error('I am finally Exception thrown in') }) .then(res => { console.log('finally Hinder then function', res) }) .catch(err => { console.log('Capture error', err) })
The output is:
'finally1' 'Capture error' Error: I am finally Exception thrown in
14. Code Output Results
function runAsync (x) { const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000)) return p } Promise.all([runAsync(1), runAsync(2), runAsync(3)]).then(res => console.log(res))
The output is as follows:
1 2 3 [1, 2, 3]
First, a Promise is defined to execute the function runAsync asynchronously, which passes in a value x and prints out the X after an interval of one second.
Then use Promise.all executes this function, and when it executes, it sees that after one second it outputs 1, 2, 3 and an array [1, 2, 3]. The three functions are executed synchronously and all the results are returned in one callback function. The result is in the same order as the function.
15. Code Output Results
function runAsync (x) { const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000)) return p } function runReject (x) { const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x)) return p } Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)]) .then(res => console.log(res)) .catch(err => console.log(err))
The output is as follows:
// Output after 1s 1 3 // Output after 2s 2 Error: 2 // Output after 4s 4
You can see it. catch caught the first error, and the first error in this topic was the result of runReject(2). If an exception in a set of asynchronous operations does not enter. then() in the first callback function parameter. Will be. The second callback function of then() captures.
16. Code Output Results
function runAsync (x) { const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000)) return p } Promise.race([runAsync(1), runAsync(2), runAsync(3)]) .then(res => console.log('result: ', res)) .catch(err => console.log(err))
The output is as follows:
1 'result: ' 1 2 3
The then captures only the first successful method, and the other functions continue to execute, but are not captured by the then.
17. Code Output Results
function runAsync(x) { const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000) ); return p; } function runReject(x) { const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x) ); return p; } Promise.race([runReject(0), runAsync(1), runAsync(2), runAsync(3)]) .then(res => console.log("result: ", res)) .catch(err => console.log(err));
The output is as follows:
0 Error: 0 1 2 3
You can see that after catch catches the first error, the following code does not execute, but it will no longer be captured.
Note: If there are asynchronous tasks in the array passed in by all and race that throw exceptions, only the first thrown error will be caught, and it will be caught by the second parameter of the then or by the subsequent catch; However, it does not affect the execution of other asynchronous tasks in the array.
18. Code Output Results
async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } async function async2() { console.log("async2"); } async1(); console.log('start')
The output is as follows:
async1 start async2 start async1 end
The code is executed as follows:
- The synchronization code async1 start in the function is executed first, then await is encountered, which blocks the execution of the code behind async1, so async2 in async2 is executed first, then async1 is skipped.
- After jumping out of the async1 function, execute the synchronization code start;
- After a full round of macro tasks has been executed, execute the content after await async1 end.
It can be understood here that the statement following await is equivalent to placing it in a new Promise, and the statement following the next line is equivalent to placing it in a Promise. In the.
19. Code Output Results
async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); setTimeout(() => { console.log('timer1') }, 0) } async function async2() { setTimeout(() => { console.log('timer2') }, 0) console.log("async2"); } async1(); setTimeout(() => { console.log('timer3') }, 0) console.log("start")
The output is as follows:
async1 start async2 start async1 end timer2 timer3 timer1
The code is executed as follows:
- First enter async1 and print out async1 start;
- Encountered async2, entered async2, encountered timer timer2, joined the macro task queue, and then printed async2;
- Since async2 blocks the execution of the following code, execute the following timer timer3, join it to the macro task queue, and print start;
- Then execute the code behind async2, print out async1 end, encounter timer timer1, and add it to the macro task queue;
- Finally, the macro task queue has three tasks, timer2, timer3, timer1, and no micro-tasks, so all direct macro tasks are executed according to the FIFO principle.
20. Code Output Results
async function async1 () { console.log('async1 start'); await new Promise(resolve => { console.log('promise1') }) console.log('async1 success'); return 'async1 end' } console.log('srcipt start') async1().then(res => console.log(res)) console.log('srcipt end')
The output is as follows:
script start async1 start promise1 script end
It is important to note here that Promise following await in async1 has no return value, that is, its state is always pending, so content following await will not execute, including that following async1. then.
21. Code Output Results
async function async1 () { console.log('async1 start'); await new Promise(resolve => { console.log('promise1') resolve('promise1 resolve') }).then(res => console.log(res)) console.log('async1 success'); return 'async1 end' } console.log('srcipt start') async1().then(res => console.log(res)) console.log('srcipt end')
This is a modification of the above question, with resolution added.
The output is as follows:
script start async1 start promise1 script end promise1 resolve async1 success async1 end
22. Code Output Results
async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } async function async2() { console.log("async2"); } console.log("script start"); setTimeout(function() { console.log("setTimeout"); }, 0); async1(); new Promise(resolve => { console.log("promise1"); resolve(); }).then(function() { console.log("promise2"); }); console.log('script end')
The output is as follows:
script start async1 start async2 promise1 script end async1 end promise2 setTimeout
The code is executed as follows:
- Two functions, async1 and async2, are defined at the beginning, but they are not executed. The code in the script is executed, so the script start is printed.
- Encountered timer Settimeout, which is a macro task and joins it to the macro task queue;
- Then the function async1 is executed, and async1 start is printed out first.
- Encountering await, execute async2, print out async2, and block the execution of the following code, adding the latter code to the microtask queue;
- Then jump out of async1 and async2, encounter Promise, print out promise1;
- When a resolution is encountered, join it to the microtask queue, then execute the script code that follows and print out the script end;
- Then it's time to queue the microtasks. First print out async1 end, then print out promise2.
- After the micro task queue is executed, the timer in the macro task queue is executed and the setTimeout is printed out.
23. Code Output Results
async function async1 () { await async2(); console.log('async1'); return 'async1 success' } async function async2 () { return new Promise((resolve, reject) => { console.log('async2') reject('error') }) } async1().then(res => console.log(res))
The output is as follows:
async2 Uncaught (in promise) error
You can see that if an error is thrown in the async function, the error result will be terminated and the execution will not continue down.
If you want the code behind the error to execute, you can use catch to capture:
async function async1 () { await Promise.reject('error!!!').catch(e => console.log(e)) console.log('async1'); return Promise.resolve('async1 success') } async1().then(res => console.log(res)) console.log('script start')
The result of this output is:
script start error!!! async1 async1 success
24. Code Output Results
const first = () => (new Promise((resolve, reject) => { console.log(3); let p = new Promise((resolve, reject) => { console.log(7); setTimeout(() => { console.log(5); resolve(6); console.log(p) }, 0) resolve(1); }); resolve(2); p.then((arg) => { console.log(arg); }); })); first().then((arg) => { console.log(arg); }); console.log(4);
The output is as follows:
3 7 4 1 2 5 Promise{<resolved>: 1}
The code is executed as follows:
- First it enters Promise, prints out 3, then enters Promise below, prints out 7;
- Encountered a timer to join the macro task queue;
- Executes resolution in Promise p, the state changes to resolve d, and the return value is 1;
- Executes resolution in Promise first, the state changes to resolve d, and the return value is 2;
- Encountered p.then, joined the microtask queue, and encountered first().then, add it to the task queue;
- Execute external code, print out 4;
- This completes the first macro task, starts executing the tasks in the microtask queue, and prints out 1 and 2 successively.
- Then the micro task is finished and the next macro task is executed. There is a timer in the macro task queue, execute it and print out 5. resolve(6) will not execute because the execution has changed to resolved state.
- Last console.log(p) Print out Promise {<resolved>: 1};
25. Code Output Results
const async1 = async () => { console.log('async1'); setTimeout(() => { console.log('timer1') }, 2000) await new Promise(resolve => { console.log('promise1') }) console.log('async1 end') return 'async1 success' } console.log('script start'); async1().then(res => console.log(res)); console.log('script end'); Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .catch(4) .then(res => console.log(res)) setTimeout(() => { console.log('timer2') }, 1000)
The output is as follows:
script start async1 promise1 script end 1 timer2 timer1
The code is executed as follows:
- First execute the sync band, print out the script start;
- Encountered timer timer1 to join the macro task queue;
- Then Promise is executed, and promise1 is printed out. Since Promise does not return a value, the following code will not execute.
- Then execute the synchronization code and print out the script end;
- Continue with the Promise below. The N and. catch expects the parameter to be a function, where a number is passed in, so value penetration occurs, passing the value of resolve(1) to the last then and printing out 1 directly;
- Encounters the second timer, joins it to the microtask queue, executes the microtask queue, executes two timers in sequence, but due to the timer time, prints timer2 after two seconds and timer1 after four seconds.
26. Code Output Results
const p1 = new Promise((resolve) => { setTimeout(() => { resolve('resolve3'); console.log('timer1') }, 0) resolve('resovle1'); resolve('resolve2'); }).then(res => { console.log(res) // resolve1 setTimeout(() => { console.log(p1) }, 1000) }).finally(res => { console.log('finally', res) })
The results are as follows:
resolve1 finally undefined timer1 Promise{<resolved>: undefined}
27. Code Output Results
console.log('1'); setTimeout(function() { console.log('2'); process.nextTick(function() { console.log('3'); }) new Promise(function(resolve) { console.log('4'); resolve(); }).then(function() { console.log('5') }) }) process.nextTick(function() { console.log('6'); }) new Promise(function(resolve) { console.log('7'); resolve(); }).then(function() { console.log('8') }) setTimeout(function() { console.log('9'); process.nextTick(function() { console.log('10'); }) new Promise(function(resolve) { console.log('11'); resolve(); }).then(function() { console.log('12') }) })
The output is as follows:
1 7 6 8 2 4 3 5 9 11 10 12
(1) The first round of event cycle process is analyzed as follows:
- The whole script enters the main thread as the first macro task and encounters console.log, output 1.
- When setTimeout is encountered, its callback function is distributed to the macro task Event Queue. For the time being, it is set Timeout1.
- Process encountered. NextTick(), whose callback functions are distributed to the microtask Event Queue. It is marked process1.
- Encountered Promise, new Promise executes directly, output 7. The n is distributed to the microtask Event Queue. It is marked then1.
- SetTimeout was encountered again, and its callback function was distributed to the macro task Event Queue, which is named setTimeout2.
Macro Task Event Queue | Microtask Event Queue |
---|---|
setTimeout1 | process1 |
setTimeout2 | then1 |
The above table is the case for each Event Queue at the end of the first event loop macro task, where 1 and 7 have been output. Two microtasks, process1 and then1, were found:
- Execute process1, output 6.
- Execute then1, output 8.
The first round of events formally ends, and the result of this round is output 1, 7, 6, 8.
(2) The second round of time cycle starts with the **setTimeout1** macro task:
- Output 2 first. Next we encountered process.nextTick(), which is also distributed to the microtask Event Queue, is named process2.
- The new Promise immediately executes output 4, and the n is also distributed to the microtask Event Queue, which is named then2.
Macro Task Event Queue | Microtask Event Queue |
---|---|
setTimeout2 | process2 |
then2 |
At the end of the second round of event loop macro tasks, two microtasks, process2 and then2, were found to be executable:
- Output 3.
- Output 5.
The second round of event loops ends, and the second round outputs 2, 4, 3, 5.
(3) The third round of event loop begins, and at this time only setTimeout2 remains, execute.
- Direct output 9.
- Will process.nextTick() is distributed to the microtask Event Queue. It is marked process3.
- Execute new Promise directly, output 11.
- Distribute the then to the microtask Event Queue, marked then3.
Macro Task Event Queue | Microtask Event Queue |
---|---|
process3 | |
then3 |
The third round of event loop macro task execution ends, executing two micro tasks process3 and then3:
- Output 10.
- Output 12.
The third round of event cycle ends, and the third round outputs 9, 11, 10, 12.
The entire code, there are three event loops, the complete output is 1, 7, 6, 8, 2, 4, 3, 5, 9, 11, 10, 12.
28. Code Output Results
console.log(1) setTimeout(() => { console.log(2) }) new Promise(resolve => { console.log(3) resolve(4) }).then(d => console.log(d)) setTimeout(() => { console.log(5) new Promise(resolve => { resolve(6) }).then(d => console.log(d)) }) setTimeout(() => { console.log(7) }) console.log(8)
The output is as follows:
1 3 8 4 2 5 6 7
The code is executed as follows:
- First execute the script code and print out 1;
- Encountered the first timer and joined the macro task queue;
- Encountered Promise, executed the code, printed out 3, encountered resolve, and joined the microtask queue;
- Meet the second timer and join the macro task queue;
- Meet the third timer and join the macro task queue;
- Continue executing script code, print out 8, the first round of execution ends;
- Execute the microtask queue and print out the resolve result of the first Promise: 4;
- Start the macro task queue, execute the first timer, print out 2;
- At this time, there is no micro task, continue to execute the second timer in the macro task, first print out 5, encounter Promise, preferred print out 6, encounter resolve, join it to the micro task queue;
- Execute micro task queue, print out 6;
- Execute the last timer in the macro task queue, printing out 7.
29. Code Output Results
console.log(1); setTimeout(() => { console.log(2); Promise.resolve().then(() => { console.log(3) }); }); new Promise((resolve, reject) => { console.log(4) resolve(5) }).then((data) => { console.log(data); }) setTimeout(() => { console.log(6); }) console.log(7);
The code output is as follows:
1 4 7 5 2 3 6
The code is executed as follows:
- First execute the scrip code and print out 1;
- Encounters the first timer setTimeout and joins it to the macro task queue;
- Encounters Promise, executes the sync code inside, prints out 4, encounters Resolution, and joins it to the microtask queue;
- Encountered the second timer setTimeout and added it to the red task queue;
- Execute script code, print out 7, until the first execution is complete;
- Specify the code in the microtask queue and print out the resolve result: 5;
- Execute the first timer setTimeout in the macro task, print out 2 first, and encounter Promise.resolve().then(), add it to the microtask queue;
- After the macro task is executed, the micro task queue is executed, printing out 3;
- Continue executing the second timer in the macro task queue, printing out 6.
30. Code Output Results
Promise.resolve().then(() => { console.log('1'); throw 'Error'; }).then(() => { console.log('2'); }).catch(() => { console.log('3'); throw 'Error'; }).then(() => { console.log('4'); }).catch(() => { console.log('5'); }).then(() => { console.log('6'); });
The results are as follows:
1 3 5 6
In this topic, we need to know that if throw throws an error, it will be caught by the catch, and if no throw throws an error, it will continue to execute the following then.
31. Code Output Results
setTimeout(function () { console.log(1); }, 100); new Promise(function (resolve) { console.log(2); resolve(); console.log(3); }).then(function () { console.log(4); new Promise((resove, reject) => { console.log(5); setTimeout(() => { console.log(6); }, 10); }) }); console.log(7); console.log(8);
The output is:
2 3 7 8 4 5 6 1
The code is executed as follows:
- First encounter the timer and join it to the macro task queue;
- Encountered Promise, first execute the synchronization code inside, print out 2, encounter resolution, join it to the micro task queue, execute the synchronization code behind, print out 3;
- Continue executing the code in script, print out 7 and 8, and the first round of code execution is complete.
- Execute the code in the micro task queue, print out 4 first, if you encounter Promise, execute the synchronization code in it, print out 5, encounter timer, add it to the macro task queue, there are two timers in the macro task queue;
- Execute the code in the macro task queue, here we need to note that the first timer is 100ms, the second timer is 10ms, so execute the second timer first and print out 6;
- At this time, the micro task queue is empty, continue to execute the macro task queue, print out 1.
When we finish this topic, we need to pay special attention to the fact that not all timers have a time of 0.
2. this
1. Code Output Results
function foo() { console.log( this.a ); } function doFoo() { foo(); } var obj = { a: 1, doFoo: doFoo }; var a = 2; obj.doFoo()
Output result: 2
In Javascript, this points to the current object at the time the function executes. When foo is executed, the execution environment is the doFoo function, and the execution environment is global. So this in foo is pointing to window, so it prints out 2.
2. Code Output Results
var a = 10 var obj = { a: 20, say: () => { console.log(this.a) } } obj.say() var anotherObj = { a: 30 } obj.say.apply(anotherObj)
Output result: 10 10
As we know, the arrow function does not bind this, its this comes from the context of its parent, so it first prints a value of 10 in the global. Although the say method is pointed to another object later, it still cannot change the properties of the arrow function. Its this still points to the global, so it still outputs 10.
However, if it is a normal function, then the result will be completely different:
var a = 10 var obj = { a: 20, say(){ console.log(this.a) } } obj.say() var anotherObj={a:30} obj.say.apply(anotherObj)
Output result: 20 30
In this case, this in the say method points to its object and outputs the value of a in it.
3. Code Output Results
function a() { console.log(this); } a.call(null);
Print result: window object
According to the ECMAScript262 specification, if the object caller passed in by the first parameter is null or undefined, the call method will take the global object (a window object on the browser) as the value of this. So, whether null or undefined is passed in, this is the global object window. So the answer on the browser is to output a window object.
Note that in strict mode, null is null and undefined is undefined:
'use strict'; function a() { console.log(this); } a.call(null); // null a.call(undefined); // undefined
4. Code Output Results
var obj = { name: 'cuggz', fun: function(){ console.log(this.name); } } obj.fun() // cuggz new obj.fun() // undefined
6. Code Output Results
var obj = { say: function() { var f1 = () => { console.log("1111", this); } f1(); }, pro: { getPro:() => { console.log(this); } } } var o = obj.say; o(); obj.say(); obj.pro.getPro();
var obj = { say: function() { var f1 = () => { console.log("1111", this); } f1(); }, pro: { getPro:() => { console.log(this); } } } var o = obj.say; o(); obj.say(); obj.pro.getPro();
Output results:
1111 window object 1111 obj object window object
Resolution:
- o(), o is executed globally, and f1 is an arrow function, it is not bound to this, its this points to this of its parent, its this of its parent say method points to the global scope, so it prints out the window;
- obj.say(), whoever calls say, this of say points to whoever, so this point to an obj object at this time;
- obj.pro.getPro(), we know that the arrow function does not bind this, getPro is in pro, and the object does not form a separate scope, so the function this of the arrow points to the global scope window.
7. Code Output Results
var myObject = { foo: "bar", func: function() { var self = this; console.log(this.foo); console.log(self.foo); (function() { console.log(this.foo); console.log(self.foo); }()); } }; myObject.func();
Output result: bar undefined bar
Resolution:
- First the func is called by myObject, and this points to myObject. Because var self = this; So self points to myObject.
- This immediate execution anonymous function expression is called by window, where this points to window. The scope for immediate execution of anonymous functions is myObject. In the scope of func, the self variable cannot be found in this scope. Look up the scope chain for the self variable and find the self pointing to the myObject object.
8. Code Output Problems
window.number = 2; var obj = { number: 3, db1: (function(){ console.log(this); this.number *= 4; return function(){ console.log(this); this.number *= 5; } })() } var db1 = obj.db1; db1(); obj.db1(); console.log(obj.number); // 15 console.log(window.number); // 40
The title may seem a bit confusing, but it's actually looking at what this is pointing to:
- When db1() is executed, this points to the global scope, so window.number * 4 = 8, then executes the anonymous function, so window.number * 5 = 40;
- Execute obj.db1(); When this points to an obj object and executes an anonymous function, so obj.numer * 5 = 15.
9. Code Output Results
var length = 10; function fn() { console.log(this.length); } var obj = { length: 5, method: function(fn) { fn(); arguments[0](); } }; obj.method(fn, 1);
Output result: 10 2
Resolution:
- The first fn() executes, this points to the window object, and outputs 10.
- Execute arguments a second time 0 , which is equivalent to the arguments call method, this points to arguments, and here two parameters are passed, so the output arguments length is 2.
10. Code Output Results
var a = 1; function printA(){ console.log(this.a); } var obj={ a:2, foo:printA, bar:function(){ printA(); } } obj.foo(); // 2 obj.bar(); // 1 var foo = obj.foo; foo(); // 1
Output result: 2 1 1
Resolution:
- obj.foo(), this of foo points to the obj object, so a outputs 2;
- obj.bar(), printA is executed in the bar method, so this time printA's this points to window, so it outputs 1;
- foo(), foo is executed in a global object, so its this points to window, so it outputs 1;
11. Code Output Results
var x = 3; var y = 4; var obj = { x: 1, y: 6, getX: function() { var x = 5; return function() { return this.x; }(); }, getY: function() { var y = 7; return this.y; } } console.log(obj.getX()) // 3 console.log(obj.getY()) // 6
Output result: 3 6
Resolution:
- We know that this of the anonymous function points to a global object, so this points to window and prints out 3;
- getY is called by obj, so its this points to the obj object and prints out 6.
12. Code Output Results
var a = 10; var obt = { a: 20, fn: function(){ var a = 30; console.log(this.a) } } obt.fn(); // 20 obt.fn.call(); // 10 (obt.fn)(); // 20
Output result: 20 10 20
Resolution:
- obt.fn(), fn is called by obt, so its this points to the obt object and prints out 20;
- obt.fn.call(), where the call's argument is null without writing anything, we know that if the call's argument is undefined or null, this will point to the global object this, so it will print out 10;
- (obt.fn)(), parentheses are used to change the order in which the expression is run, but they have no effect here with or without parentheses; Equivalent to obt.fn(), so it prints out 20;
13. Code Output Results
function a(xx){ this.x = xx; return this }; var x = a(5); var y = a(6); console.log(x.x) // undefined console.log(y.x) // 6
Output result: undefined 6
Resolution:
- The most critical is var x = a (5), function a is called at the global scope, so this inside the function points to the window object. ** So this.x = 5 equals: window.x = 5. ** Then return this, that is, the value of the X variable in var x = a(5) is window, where x overrides the value of X inside the function. Then execute console.log(x.x), also known as console.log(window.x), and the window object has no X attribute, so undefined is output.
- When pointing to y.x, X in the global variable is assigned a value of 6, so 6 is printed.
14. Code Output Results
function foo(something){ this.a = something } var obj1 = { foo: foo } var obj2 = {} obj1.foo(2); console.log(obj1.a); // 2 obj1.foo.call(obj2, 3); console.log(obj2.a); // 3 var bar = new obj1.foo(4) console.log(obj1.a); // 2 console.log(bar.a); // 4
Output result: 23 2 4
Resolution:
- Execute obj1 first. Foo(2); The a attribute is added to obj with a value of 2. Then obj1 is executed. A, A is called by right obj1, so this points to obj and prints out 2;
- Execute obj1.foo.call(obj2, 3) will point foo's this at obj2, followed by the same as above, so print out 3;
- obj1.a will print out 2;
- Finally, consider the priority of this binding. The new binding has a higher priority than the implicit binding, so it outputs 4.
15. Code Output Results
function foo(something){ this.a = something } var obj1 = {} var bar = foo.bind(obj1); bar(2); console.log(obj1.a); // 2 var baz = new bar(3); console.log(obj1.a); // 2 console.log(baz.a); // 3
Output result: 22 3
This topic is similar to the one above, mainly examining the priority of this binding. Just remember the following conclusion: **This binding's priority: **new binding>explicit binding>implicit binding>default binding.
3. Scope-Variable Promotion-Closure
1. Code Output Results
(function(){ var x = y = 1; })(); var z; console.log(y); // 1 console.log(z); // undefined console.log(x); // Uncaught ReferenceError: x is not defined
The key to this code is: var x = y = 1; In fact, this is a right-to-left execution, first y = 1, because y is a global variable because it is not declared with var, then the second step is to assign y to x, say a global variable to a local variable, and finally, x is a local variable and Y is a global variable, so printing x is an error.
2. Code Output Results
var a, b (function () { console.log(a); console.log(b); var a = (b = 3); console.log(a); console.log(b); })() console.log(a); console.log(b);
Output results:
undefined undefined 3 3 undefined 3
undefined undefined 3 3 undefined 3
This topic is similar to the one examined above, where b is assigned 3, b is a global variable, and 3 is assigned to a, A is a local variable, so a is still undefined at the end of printing.
3. Code Output Results
var friendName = 'World'; (function() { if (typeof friendName === 'undefined') { var friendName = 'Jack'; console.log('Goodbye ' + friendName); } else { console.log('Hello ' + friendName); } })();
Output result: Goodbye Jack
We know that in JavaScript, both Function and var are promoted (variable promotion), so the code above is equivalent to:
var name = 'World!'; (function () { var name; if (typeof name === 'undefined') { name = 'Jack'; console.log('Goodbye ' + name); } else { console.log('Hello ' + name); } })();
In this way, the answer is clear.
4. Code Output Results
function fn1(){ console.log('fn1') } var fn2 fn1() fn2() fn2 = function() { console.log('fn2') } fn2()
Output results:
fn1 Uncaught TypeError: fn2 is not a function fn2
Here we are also looking at variable promotion, the key is the first fn2(), at which point FN2 is still an undefined variable, so FN2 is not a function.
5. Code Output Results
function a() { var temp = 10; function b() { console.log(temp); // 10 } b(); } a(); function a() { var temp = 10; b(); } function b() { console.log(temp); // Error Uncaught ReferenceError: temp is not defined } a();
In the above two sections of code, the first section can be output normally, this should not be a problem, the key is the second section of code, it will error Uncaught ReferenceError: temp is not defined. This is because temp is undefined when method b executes.
6. Code Output Results
var a=3; function c(){ alert(a); } (function(){ var a=4; c(); })();
The scope chain of variables in js is related to the environment at the time of definition and not to execution. The execution environment only changes this, parameters passed, global variables, and so on
7. Code Output Problems
function fun(n, o) { console.log(o) return { fun: function(m){ return fun(m, n); } }; } var a = fun(0); a.fun(1); a.fun(2); a.fun(3); var b = fun(0).fun(1).fun(2).fun(3); var c = fun(0).fun(1); c.fun(2); c.fun(3);
Output results:
undefined 0 0 0 undefined 0 1 2 undefined 0 1 1
This is a topic about closures, and for fun methods, an object is returned after the call. We know that when a function is called, fewer arguments are passed in than when the function is declared, and the remaining parameters are set to undefined values. So console.log(o); Will output undefined. And a is the object that fun(0) returns. That is, the value of the parameter n in the function fun is 0, and the object returned needs a parameter n, and if there is no N in the scope of this object, it continues to search for N in the scope up to the next level, and finally finds n in the function fun, where the value of n is 0. With this in mind, other operations are simple, and so on.
8. Code Output Results
f = function() {return true;}; g = function() {return false;}; (function() { if (g() && [] == ![]) { f = function f() {return false;}; function g() {return true;} } })(); console.log(f());
Output result: false
First, two variables f and G are defined, and we know that variables can be reassigned. Following is an anonymous self-executing function that calls the function g() in the if condition. Since in the anonymous function, the function g is redefined, which overrides the externally defined variable g, the internal function g method is called, returning true. The first condition passes into the second condition.
The second condition is [] ==! [], look first! [], in JavaScript, when used for Boolean operations, such as here, a non-null reference to an object is treated as true, and a null reference is treated as false. Since this is not a null, but an array without elements, [] is considered true, and! [] The result is false. When a Boolean value participates in a conditional operation, true is considered 1, and false is considered 0. Now the condition becomes a problem of [] == 0. When an object participates in a condition comparison, it is evaluated. The result of the evaluation is an array of strings, [] is', and''is treated as 0, so the condition is true.
Both conditions are true, so the code in the condition is executed, f is defined without var, so he is a global variable. Therefore, the external variable f is accessed through the closure, reassigned, and the return value of the F function is now false. G does not have this problem, here is a G defined within a function, which does not affect the external g function. So the final result is false.
4. Prototype-Inheritance
1. Code Output Results
function Person(name) { this.name = name } var p2 = new Person('king'); console.log(p2.__proto__) //Person.prototype console.log(p2.__proto__.__proto__) //Object.prototype console.log(p2.__proto__.__proto__.__proto__) // null console.log(p2.__proto__.__proto__.__proto__.__proto__)//null missing, error console.log(p2.__proto__.__proto__.__proto__.__proto__.__proto__)//null missing, error console.log(p2.constructor)//Person console.log(p2.prototype)//undefined p2 is an instance and has no prototype attribute console.log(Person.constructor)//Function An empty function console.log(Person.prototype)//Print out Person.prototype All methods and properties in this object console.log(Person.prototype.constructor)//Person console.log(Person.prototype.__proto__)// Object.prototype console.log(Person.__proto__) //Function.prototype console.log(Function.prototype.__proto__)//Object.prototype console.log(Function.__proto__)//Function.prototype console.log(Object.__proto__)//Function.prototype console.log(Object.prototype.__proto__)//null
This topic examines the basis of the prototype, the chain of prototypes, and remembers it.
2. Code Output Results
// a function Foo () { getName = function () { console.log(1); } return this; } // b Foo.getName = function () { console.log(2); } // c Foo.prototype.getName = function () { console.log(3); } // d var getName = function () { console.log(4); } // e function getName () { console.log(5); } Foo.getName(); // 2 getName(); // 4 Foo().getName(); // 1 getName(); // 1 new Foo.getName(); // 2 new Foo().getName(); // 3 new new Foo().getName(); // 3
Output result: 24 1 1 2 3
Resolution:
- **Foo.getName(), **Foo is a function object, objects can have attributes, the getName property of Foo defined at b is a function, output 2;
- **getName(),**Look at d and e here, d is a function expression and e is a function declaration. The difference between them is that the variable is promoted, and 5 of the function declaration is overridden by 4 of the back function expression.
- **Foo().getName(),** Look at a here and re-assign the global getName to console inside Foo. Log(1), execute Foo() to return this, this this points to window, Foo().getName() is window.getName(), output 1;
- **getName(),**In the 3 above, the global getName has been reassigned, so the output here is still 1;
- **new Foo.getName(), ** This is equivalent to new (Foo.getName()), execute Foo first. GetName(), output 2, and newan instance;
- **new Foo().getName(), ** This is equivalent to (new Foo()).getName(), which first executes an instance of Foo, then executes the getName method for that instance, but the instance itself does not have this method, so de-prototype chain_u protot_u Look up, instance. protot === Foo.prototype, so output 3;
- **new new Foo().getName(),** This is equivalent to new (new Foo().getName(), as in 6 above, outputs 3 first, then newa new Foo(). Instance of getName().
3. Code Output Results
var F = function() {}; Object.prototype.a = function() { console.log('a'); }; Function.prototype.b = function() { console.log('b'); } var f = new F(); f.a(); f.b(); F.a(); F.b()
Output results:
a Uncaught TypeError: f.b is not a function a b
Resolution:
- F is not an instance of Function because it is not a constructor, it calls properties and methods on the Function prototype chain, and it can only access the Object prototype chain. So f.a() outputs a, and f.b() errors.
- F is a constructor, and F is an instance of the constructor Function. Because F instanceof Object == true and F instanceof Function === true, it can be concluded that F is an instance of both Object and Function, that is, F can access a and B. So F.a() outputs a, F.b() outputs B.
4. Code Output Results
function Foo(){ Foo.a = function(){ console.log(1); } this.a = function(){ console.log(2) } } Foo.prototype.a = function(){ console.log(3); } Foo.a = function(){ console.log(4); } Foo.a(); let obj = new Foo(); obj.a(); Foo.a();
Output result: 42 1
Resolution:
- Foo.a() This is the static method a that calls the Foo function. Although Foo has a higher priority attribute method a, Foo is not called at this time, so the result of the static method a of Foo is output at this time:4
- let obj = new Foo(); The function is called using the new method and the function instance object is returned. At this time, the property method inside the Foo function is initialized and the prototype chain is established.
- obj.a(); Call method a on the obj instance, where there are currently two a methods: one is the internal property method and the other is the method on the prototype. When both are present, look for ownProperty first, and if not, go to the prototype chain, so call the a output on the instance:2
- Foo.a(); From step 2, it is known that the attribute method inside the Foo function has been initialized, overriding the static method with the same name, so the output is:1
5. Code Output Results
function Dog() { this.name = 'puppy' } Dog.prototype.bark = () => { console.log('woof!woof!') } const dog = new Dog() console.log(Dog.prototype.constructor === Dog && dog.constructor === Dog && dog instanceof Dog)
Output result:true
Resolution:
Because constructor is a property on prototype, dog. A constructor actually points to a Dog.prototype.constructor; The constructor property points to the constructor. instanceof actually detects whether the type is on the prototype chain of the instance.
The constructor is a property on the prototype, which is easily ignored. Constructor and instanceof work differently. Sensitively, constructor is more restrictive, it can only strictly compare whether an object's constructor is a specified value. Instanceof is looser and returns true as long as the detected type is on the prototype chain.
6. Code Output Results
var A = {n: 4399}; var B = function(){this.n = 9999}; var C = function(){var n = 8888}; B.prototype = A; C.prototype = A; var b = new B(); var c = new C(); A.n++ console.log(b.n); console.log(c.n);
Output result: 9999 4400
Resolution:
- console.log(b.n), the first step in finding B.N is to find if the B object itself has an n attribute, and if it is not to be found on a prototype, this is inside the function when var b = new B() is executed. N=9999 (where this points to b) returns a B object, which has its own n attribute, so it returns 9999.
- console.log(c.n), similarly, when var c = new C() is executed, the C object does not have its own n attribute, look up to find the N attribute on the prototype, because A.n++ (in this case, n in object A is 4400), so it returns 4400.
7. Code Output Problems
function A(){ } function B(a){ this.a = a; } function C(a){ if(a){ this.a = a; } } A.prototype.a = 1; B.prototype.a = 1; C.prototype.a = 1; console.log(new A().a); console.log(new B().a); console.log(new C(2).a);
Output result: 1 undefined 2
Resolution:
- console.log(new A().a), new A() object created for the constructor does not have a property of a itself, so look to its prototype and find that the property value of a property of the prototype is 1, so the output value is 1;
- Console. Log(new B()). A), ew B() is the object created for the constructor, which has a parameter a, but the object does not pass a parameter, so the output value is undefined;
- Console. Log(new C(2)). A), new C() is the object created for the constructor, which has a parameter a and passes an argument of 2. Inside the executor, if found to be true, execute this.a = 2, so attribute a has a value of 2.
8 Code Output Problems
function Parent() { this.a = 1; this.b = [1, 2, this.a]; this.c = { demo: 5 }; this.show = function () { console.log(this.a , this.b , this.c.demo ); } } function Child() { this.a = 2; this.change = function () { this.b.push(this.a); this.a = this.b.length; this.c.demo = this.a++; } } Child.prototype = new Parent(); var parent = new Parent(); var child1 = new Child(); var child2 = new Child(); child1.a = 11; child2.a = 12; parent.show(); child1.show(); child2.show(); child1.change(); child2.change(); parent.show(); child1.show(); child2.show();
Output results:
parent.show(); // 1 [1,2,1] 5 child1.show(); // 11 [1,2,1] 5 child2.show(); // 12 [1,2,1] 5 parent.show(); // 1 [1,2,1] 5 child1.show(); // 5 [1,2,1,11,12] 5 child2.show(); // 6 [1,2,1,11,12] 5
This topic is worth emperor's attention. He involves many points of knowledge, such as the direction of this, prototype, prototype chain, class inheritance, data type, and so on.
Resolution**:**
- parent.show(), you can get the value you need directly, nothing to say;
- child1.show(), Child's constructor was originally meant to point to Child, and the title explicitly points the prototype object of the Child class to an instance of the Parent class, noting Child.prototype points to the instance parent of Parent, not to the class Parent.
- child2.show(), there's nothing to say about this;
- parent.show(), parent is an instance of the Parent class, Child. The prorotype points to another instance of the Parent class, and the two do not affect each other in heap memory, so the above operation does not affect the parent instance, so the output will not change.
- child1. What happened after show(), child1 executed the change() method?
- this.b.push(this.a), because of the dynamic pointing characteristic of this, this.b will point to Child. b array on prototype, this. A will point to the a property of child1, so Child.prototype.b became **[1,2,1,11]**;
- this.a = this.b.length, this in this statement. A and this.b points in the same direction as the previous sentence, so the result is child1.a becomes 4;
- this.c.demo = this.a++, since child1 does not have the c attribute itself, this is here. c will point to Child.prototype.c, this. The a value is 4, which is the original type, so the assignment will be done directly, Child.prototype.c.demo results in 4, while this.a then increases to 5 (4 + 1 = 5).
- Child2 executes the change() method, and both child2 and Child1 are instances of the Child class, so their prototype chain points to the same prototype object, Child.prototype, which is the same parent instance, so child2. All statements in change() that affect the prototype object affect the final output of child1.
- this.b.push(this.a), because of the dynamic pointing characteristic of this, this.b will point to Child. b array on prototype, this. A will point to the a property of child2, so Child.prototype.b became **[1,2,1,11,12]**;
- this.a = this.b.length, this in this statement. A and this.b points in the same direction as the previous sentence, so the result is child2.a becomes 5;
- this.c.demo = this.a++, since child2 does not have the C attribute itself, this is here. C will point to Child.prototype.c, so the result of execution is Child. Prototype. The value of c.demo changes to child2.a has a value of 5, while child2.a eventually increases to 6 (5 + 1 = 6).
9. Code Output Results
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function (){ return this.subproperty; }; var instance = new SubType(); console.log(instance.getSuperValue());
Output result:true
In fact, this code implements prototype chain inheritance, SubType inherits SuperType, essentially rewriting the prototype object of SubType and replacing it with an instance of a new type. The prototype of SubType is rewritten, so instance. The constructor points to SuperType. Specifically as follows: