交互式 JavaScript 面试练习

执行上下文面试实验室

使用 DeepJS 执行可视化器练习真实的 JavaScript 面试题,先预测输出结果,再一步步追踪结果究竟是如何产生的。

  1. 为什么函数中的局部变量输出 undefined?

    声明实例化

    函数内的 var 声明会在赋值语句执行前创建局部绑定。

    开始解题
  2. 当形参与局部 var 变量同名时会发生什么?

    词法作用域

    与已存在的形参同名的 var 声明不会创建新绑定,而是复用形参的绑定。

    开始解题
  3. 函数读取的是调用者的变量,还是定义时所在作用域的变量?

    词法作用域

    JavaScript 采用词法(静态)作用域,函数的作用域链在定义时就已确定,与谁调用它无关。

    开始解题
  4. 全局代码能读取函数内部声明的变量吗?

    词法作用域

    函数内部的 var 绑定对外层全局环境不可见。

    开始解题
  5. 为什么 x 开始是函数,后来变成了数字?

    声明实例化

    声明实例化只创建一个绑定,后续赋值会替换其中保存的值。

    开始解题
  6. 为什么 var 会离开 if 代码块?

    声明实例化

    var 属于函数或脚本作用域,而不属于 if 代码块。

    开始解题
  7. 未声明的赋值何时会创建全局变量?

    全局绑定

    非严格脚本对无法解析名称的赋值可能在全局对象上创建属性。

    开始解题
  8. 哪些赋值修改参数、局部变量或全局变量?

    词法作用域

    参数 a 和局部 b 遮蔽全局变量,而 c 会解析到外层绑定。

    开始解题
  9. 函数绑定为什么会变成数字?

    函数调用

    函数声明先初始化 a,随后 var 初始化器又用 2 覆盖同一个绑定。

    开始解题
  10. 修改参数会改变外层的基本类型变量吗?

    函数调用

    参数接收数字值的副本,并保存在独立的函数绑定中。

    开始解题
  11. 闭包如何保存不断变化的状态?

    闭包

    fn 返回后,返回的函数仍然可以访问 fn 的 n 绑定。

    开始解题
  12. 为什么三个 setTimeout 回调都打印 3,而不是 0、1、2?

    闭包

    var 在整个循环中只创建一个共享绑定,所有回调最终都会读到同一个最终值。

    开始解题
  13. 为什么把 var 换成 let 就能修复这个 setTimeout 循环?

    闭包

    let 会在每次迭代时创建一个全新的 i 绑定,因此每个回调闭包捕获的都是自己独立的值。

    开始解题
  14. 不用 let,用 IIFE 能修复这个 setTimeout 循环吗?

    闭包

    立即调用一个函数并把 i 作为参数传入,会让每次迭代都拥有自己独立的参数绑定。

    开始解题