面试题答案
一键面试作用域链形成
在JavaScript中,当多层嵌套函数形成闭包且存在同名变量声明时,作用域链是由内到外一层一层查找变量的。每个函数在定义时就创建了自己的作用域,作用域链包含了该函数的局部作用域以及所有外层函数的作用域,直到全局作用域。当在函数内部访问一个变量时,首先会在自身的局部作用域中查找,如果找不到,则沿着作用域链向上一层作用域查找,直到全局作用域。如果全局作用域也没有找到该变量,在非严格模式下会创建一个全局变量(如果是使用var
声明的情况),严格模式下会抛出ReferenceError
。
变量提升
var
声明:var
声明的变量会提升到函数或全局作用域的顶部,但值不会提升,即变量声明被提升,初始化留在原地。所以在声明之前使用var
声明的变量会得到undefined
。let
和const
声明:let
和const
声明的变量存在暂时性死区(TDZ)。它们也会提升,但在声明语句之前访问这些变量会抛出ReferenceError
,而不是像var
那样得到undefined
。这意味着在变量声明之前,它们在其作用域内是不可用的。
可能出现的问题
- 变量覆盖:由于不同作用域中同名变量的存在,可能会意外地覆盖外层作用域的变量,导致逻辑错误。
- TDZ相关错误:不小心在
let
和const
声明之前访问变量会导致ReferenceError
,特别是在复杂的嵌套函数和闭包场景中容易出错。
代码示例
function outer() {
var x = 'outer var';
let y = 'outer let';
const z = 'outer const';
function inner() {
var x = 'inner var';
let y = 'inner let';
const z = 'inner const';
console.log(x); // 'inner var',优先使用内层作用域的变量
console.log(y); // 'inner let',优先使用内层作用域的变量
console.log(z); // 'inner const',优先使用内层作用域的变量
}
inner();
console.log(x); // 'outer var',内层函数没有改变外层的x
console.log(y); // 'outer let',内层函数没有改变外层的y
console.log(z); // 'outer const',内层函数没有改变外层的z
}
outer();
// 变量提升和TDZ示例
function test() {
console.log(a); // undefined,var声明提升但值未提升
console.log(b); // ReferenceError: b is not defined,let存在TDZ
console.log(c); // ReferenceError: c is not defined,const存在TDZ
var a = 'var value';
let b = 'let value';
const c = 'const value';
}
test();