JavaScript 引擎在执行代码之前,会先进行编译。在编译阶段,变量声明和函数声明会被从它们在代码中的位置移动到当前作用域的顶部。
var 提升等价于:
函数声明 会整体提升(不仅仅是变量名)。
这里的 var foo 被提升为 undefined,调用 undefined() 当然报错。
ES6 引入了 let 和 const,它们使得 {} 变为块级作用域。
TDZ (Temporal Dead Zone) 是指在使用 let 或 const 声明变量之前的代码区域。
在这段区域内,如果访问该变量,会抛出 ReferenceError。
目的:强制让开发人员在声明变量后再使用它,避免像 var 那样依赖变量提升导致的不可预测行为。
在 JavaScript 中,let/const 也是存在变量提升的。 JS 引擎在编译阶段就已经知道变量的存在(及其作用域)。
var: 声明被提升,且会被直接初始化为 undefined。所以你可以在声明前访问它(值为 undefined)。let/const: 声明被提升,但不会被初始化。直到执行流运行到声明的那一行代码时,变量才会被初始化。在初始化之前,变量处于“死区”。看似合法的赋值,实则是 TDZ。
在 TDZ 中,连以前被认为是“安全”的操作 typeof 也会报错。
类声明也不会像函数声明那样整体提升,必须先定义后使用。
在查找变量时,JS 引擎会先在当前作用域找,找不到就去外层作用域找,直到全局作用域。如果在全局还找不到,非严格模式下会自动创建全局变量(写入赋值),或者报错(读取)。
面试题:词法作用域 函数的作用域在定义时就确定了,而不是调用时。
答案:输出 2。因为 foo 是在全局作用域定义的,它的上层作用域是全局作用域(a=2),而不是 bar 的作用域。
var,let,const 区别?var 是函数作用域,let/const 是块级作用域。var 提升并初始化为 undefined;let/const 提升但不初始化(TDZ)。var 允许,let/const 报错。var a = 1 会导致 window.a === 1;let a = 1 不会挂载到 window。创建一个独立的函数作用域,避免污染全局变量。现代开发中多用模块化或块级作用域代替。