面试题答案
一键面试1. 多层嵌套函数和模块环境下的作用域链构建与变量查找机制
- 作用域链构建:
- 在TypeScript中,函数定义时会创建一个作用域。当函数嵌套时,内层函数可以访问外层函数的作用域,形成作用域链。例如:
function outer() {
let outerVar = 'outer variable';
function inner() {
let innerVar = 'inner variable';
console.log(outerVar); // 内层函数可以访问外层函数的变量
}
inner();
}
outer();
- 模块也有自己的作用域。一个模块中的顶级作用域独立于其他模块。模块内的函数和变量在模块作用域内定义,不会污染全局作用域。
- 变量查找机制:
- 当查找一个变量时,TypeScript会从当前作用域开始查找。如果在当前作用域找不到,会沿着作用域链向上查找,直到全局作用域(或模块的顶级作用域)。例如在上述代码中,
inner
函数查找outerVar
时,先在自身作用域查找,找不到则到外层outer
函数的作用域查找。
- 当查找一个变量时,TypeScript会从当前作用域开始查找。如果在当前作用域找不到,会沿着作用域链向上查找,直到全局作用域(或模块的顶级作用域)。例如在上述代码中,
2. 同名变量在不同作用域中声明时变量的确定
当存在同名变量在不同作用域中声明时,TypeScript遵循就近原则。即优先使用当前作用域内声明的变量。例如:
let globalVar = 'global';
function test() {
let globalVar = 'local';
console.log(globalVar); // 输出 'local',优先使用函数内的局部变量
}
test();
在函数test
内部,局部变量globalVar
遮蔽了全局变量globalVar
,所以使用的是局部变量。
3. 模块中export
导出函数及内部局部变量的作用域和生命周期
- 编译原理角度:
- 在编译时,TypeScript会将模块编译成JavaScript代码。当导出一个函数并引用模块内局部变量时,编译器会确保函数能够正确访问到这些变量。模块内的局部变量会被编译成闭包的形式。例如:
// moduleA.ts
let localVar = 'local in moduleA';
export function exportedFunction() {
return localVar;
}
- 编译后的JavaScript代码会通过闭包的方式保存对`localVar`的引用,即使`localVar`的声明所在的作用域已经执行完毕。
- 运行时机制角度:
- 在运行时,当其他模块导入该函数时,函数内部对局部变量的引用依然有效。
localVar
的生命周期与导出函数的生命周期相关联。只要导出函数存在,localVar
就不会被垃圾回收。因为函数持有对localVar
的引用,形成了闭包。例如:
- 在运行时,当其他模块导入该函数时,函数内部对局部变量的引用依然有效。
// main.ts
import { exportedFunction } from './moduleA';
console.log(exportedFunction()); // 输出 'local in moduleA'
- 只要`exportedFunction`还能被调用,`localVar`就能通过闭包被访问到,其作用域在`exportedFunction`内部,生命周期直到`exportedFunction`不再被引用,此时`localVar`可能会被垃圾回收机制回收。