MST

星途 面试题库

面试题:JavaScript 作用域链与块级作用域的复杂应用

假设存在以下代码结构: ```javascript function outer() { let outerVar = 'outer'; function inner() { let innerVar = 'inner'; { let blockVar = 'block'; console.log(outerVar, innerVar, blockVar); } console.log(outerVar, innerVar, blockVar); } inner(); } outer(); ``` 1. 分析这段代码执行时作用域链的变化情况。 2. 如果将 `let blockVar = 'block';` 改为 `var blockVar = 'block';`,代码输出会有什么变化,为什么?
10.5万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

1. 作用域链变化情况分析

  • 进入 outer 函数执行上下文
    • 创建 outer 函数的执行上下文,此时作用域链顶端为 outer 函数的活动对象(AO),其中包含 outerVar 变量,该变量初始化为 'outer'。同时,作用域链还包含全局执行上下文的变量对象(VO,在浏览器环境中是 window 对象)。
    • 遇到 inner 函数定义,此时 inner 函数的作用域链被创建,它的作用域链顶端为 inner 函数自身的活动对象(暂时为空,因为函数还未执行),然后指向 outer 函数的活动对象,最后指向全局执行上下文的变量对象。
  • 进入 inner 函数执行上下文
    • 创建 inner 函数的执行上下文,inner 函数的活动对象成为作用域链顶端,其中包含 innerVar 变量,初始化为 'inner'。作用域链依次为 inner 函数的活动对象、outer 函数的活动对象、全局执行上下文的变量对象。
  • 进入块级作用域
    • 当进入块级作用域 {} 时,由于 let 具有块级作用域特性,会创建一个新的块级作用域,其作用域链顶端为该块级作用域的活动对象,包含 blockVar 变量,初始化为 'block'。作用域链依次为块级作用域的活动对象、inner 函数的活动对象、outer 函数的活动对象、全局执行上下文的变量对象。所以在块级作用域内,console.log(outerVar, innerVar, blockVar); 能正确输出 outer inner block
  • 离开块级作用域
    • 块级作用域结束,块级作用域的活动对象从作用域链中移除。此时 inner 函数作用域链顶端为 inner 函数的活动对象。在 console.log(outerVar, innerVar, blockVar); 处,由于 blockVar 只存在于块级作用域内,此时块级作用域已结束,blockVar 不在作用域链中,会导致 ReferenceError

2. 改为 var blockVar = 'block'; 后的变化及原因

  • 代码输出变化:如果将 let blockVar = 'block'; 改为 var blockVar = 'block';,代码不会报错,且两次 console.log 输出均为 outer inner block
  • 原因var 没有块级作用域,只有函数作用域。当 var blockVar = 'block'; 执行时,blockVar 会被提升到 inner 函数的顶部(虽然只是声明被提升,初始化还是在原来位置)。所以在整个 inner 函数内,blockVar 都在作用域链中(在 inner 函数的活动对象里),因此两次 console.log 都能访问到 blockVar 并输出 block