JavaScript面试中经常涉及到事件循环、上下文、箭头函数、变量作用域以及ES6模块等核心概念。通过清晰的代码示例,我们深入讨论这些主题,揭示其中的关键细节。
事件循环(Event Loop)
JavaScript开发者每天都与事件循环打交道,本文通过实际代码展示了 setTimeout
、Promise
和同步代码之间的交互。通过分析回应,我们纠正了一些开发者对于Promise构造函数中执行器函数同步调用的错误观念,同时详细讨论了微任务队列和宏任务队列的执行顺序。
setTimeout(() => console.log(1), 0);
console.log(2);
new Promise(res => {
console.log(3);
res();
}).then(() => console.log(4));
console.log(5);
// 输出结果:2 3 5 4 1
在这个例子中,我们看到了 setTimeout、Promise
以及一些同步代码。
给定0
延迟,我们传递给setTimeout
的函数会同步调用还是异步调用?
- 尽管
setTimeout
函数有零延迟,回调函数是异步调用的。引擎会将回调函数放在回调队列(宏任务队列)中,并在调用栈为空时将其移至调用栈。因此,数字1
将被跳过,数字2
将首先在控制台中显示。
我们作为参数传递给 Promise
构造函数的函数会同步调用还是异步调用?
-
Promise
构造函数接受的函数参数是同步执行的。因此,在控制台中接下来要显示的数字是3
。给定零延迟,我们传递给promise
的then
处理程序的函数会同步调用还是异步调用? -
then
方法中的回调是异步执行的,即使promise
没有延迟就解决了。与setTimeout
不同的是,引擎会将promise
回调放在另一个队列中 —— 工作队列(微任务队列),在那里它将等待执行。因此,接下来进入控制台的数字是5
。
哪个优先级更高 —— 微任务队列还是宏任务队列,换句话说 —— Promise 还是 setTimeout?
微任务(Promise)比宏任务(setTimeout)有更高的优先级
,所以下一个在控制台中的数字将是4
,最后一个是1
。
通过分析回应,我们可以得出结论,大多数受访者在假设传递给 Promise 构造函数作为参数的执行器函数是异步调用的方面是错误的。
上下文(Context)
在面试中,对于 this
关键字的理解至关重要。我们通过具体的例子讨论了普通函数和箭头函数中 this
的不同行为,并解释了在不同上下文中函数调用的结果。
普通函数
'use strict';
function foo() {
console.log(this);
}
function callFoo(fn) {
fn();
}
let obj = {
foo };
callFoo