面试题答案
一键面试-
变量作用域分析:
- 在
outer
函数内部,定义了变量x
并初始化为10
。let
声明的变量具有块级作用域,这里x
的作用域是outer
函数体。 setTimeout
回调函数和inner
函数都在outer
函数内部定义,它们形成了闭包,可以访问outer
函数作用域中的x
变量。
- 在
-
事件循环执行过程分析:
- 步骤1:执行全局代码
- 首先,调用
outer
函数。在outer
函数中,声明并初始化x
为10
,然后执行setTimeout
。setTimeout
的回调函数被放入宏任务队列,其延迟为0
,但由于事件循环机制,它不会立即执行。 - 接着,将
x
的值更新为15
,并返回inner
函数,将其赋值给innerFunc
。
- 首先,调用
- 步骤2:执行
innerFunc
- 调用
innerFunc
。由于innerFunc
形成了闭包,它可以访问outer
函数作用域中的x
,此时x
的值为15
,所以输出15
。
- 调用
- 步骤3:执行全局代码剩余部分
- 输出
Global code
。此时,调用栈为空。
- 输出
- 步骤4:事件循环处理宏任务
- 事件循环开始处理宏任务队列,取出
setTimeout
的回调函数放入调用栈执行。 - 在
setTimeout
回调函数中,首先访问x
,由于闭包,这里访问的x
是outer
函数作用域中的x
,此时x
的值为15
,所以输出15
。 - 接着创建一个
Promise
,输出Promise start
,Promise
立即执行并将其then
回调放入微任务队列。 - 然后将
x
更新为20
并输出20
。
- 事件循环开始处理宏任务队列,取出
- 步骤5:事件循环处理微任务
- 调用栈再次为空,事件循环开始处理微任务队列,取出
Promise
的then
回调放入调用栈执行,输出Promise then
。
- 调用栈再次为空,事件循环开始处理微任务队列,取出
- 步骤1:执行全局代码
-
总结输出结果:
- 首先输出
15
,这是因为innerFunc
访问了outer
函数作用域中更新后的值15
。 - 接着输出
Global code
,这是全局代码的正常输出。 - 然后在
setTimeout
回调中输出15
,因为setTimeout
回调访问的x
是outer
函数作用域中的值,此时还未更新。 - 输出
Promise start
,这是Promise
创建时立即执行的输出。 - 输出
20
,这是setTimeout
回调中更新x
后的值。 - 最后输出
Promise then
,这是Promise
的then
回调执行的输出。
- 首先输出