面试题答案
一键面试1. let 和 const 在模块作用域下的特性
- let:
- 块级作用域:在模块内,
let
声明的变量具有块级作用域。这意味着在一个{}
代码块内声明的let
变量,其作用域仅限于该代码块。 - 可重新赋值:可以在声明后重新为
let
变量赋值。 - 不存在变量提升:与
var
不同,let
变量不会被提升到作用域顶部,在声明之前使用会导致ReferenceError
。
- 块级作用域:在模块内,
- const:
- 块级作用域:同
let
,const
声明的变量也具有块级作用域。 - 不可重新赋值:一旦声明并初始化,
const
变量的值就不能再被改变。 - 不存在变量提升:和
let
一样,const
变量也不存在变量提升,在声明之前使用会报错。
- 块级作用域:同
2. 复杂模块引用结构设计
假设我们有以下模块结构:
- main.ts:主模块,用于引用其他模块并展示变量行为。
- moduleA.ts:定义一些
let
和const
变量。 - moduleB.ts:引用
moduleA
并进一步操作其中的变量。
moduleA.ts
// 模块A
export let letVariable = 'Initial value of let variable';
export const constVariable = 'Initial value of const variable';
export function updateLetVariable() {
letVariable = 'Updated value of let variable';
// 以下代码会报错,因为const变量不能重新赋值
// constVariable = 'New value';
}
moduleB.ts
// 模块B
import { letVariable, constVariable, updateLetVariable } from './moduleA';
export function printVariables() {
console.log('letVariable from moduleA:', letVariable);
console.log('constVariable from moduleA:', constVariable);
}
export function updateAndPrint() {
updateLetVariable();
console.log('Updated letVariable from moduleA:', letVariable);
console.log('constVariable from moduleA:', constVariable);
}
main.ts
// 主模块
import { printVariables, updateAndPrint } from './moduleB';
printVariables();
updateAndPrint();
3. 变量在模块加载、初始化和使用过程中的差异
- 模块加载:
- 在模块加载时,
let
和const
变量都不会立即被初始化。它们处于“暂存死区”(TDZ),直到执行到声明语句。 - 例如,在
moduleA
加载时,letVariable
和constVariable
都不会被初始化,直到执行到export let letVariable = 'Initial value of let variable';
和export const constVariable = 'Initial value of const variable';
这两条语句。
- 在模块加载时,
- 初始化:
let
变量可以在声明后通过重新赋值来改变其值,如在moduleA
的updateLetVariable
函数中对letVariable
进行了重新赋值。const
变量在声明时必须初始化,并且之后不能重新赋值。
- 使用过程:
- 在跨模块引用时,
let
变量的值可以在不同模块中通过适当的导出函数进行修改。例如,在main.ts
中通过调用moduleB
的updateAndPrint
函数,间接调用moduleA
的updateLetVariable
函数来修改letVariable
的值。 const
变量的值在跨模块引用时保持不变,始终是其初始值。
- 在跨模块引用时,
4. 底层原理角度解释
- JavaScript 引擎处理:
- 在底层,JavaScript 引擎在处理模块时,会为每个模块创建一个独立的作用域。
let
和const
变量的块级作用域特性是通过词法环境(Lexical Environment)来实现的。 - 对于
let
变量,引擎会在遇到声明时在词法环境中创建一个绑定,但不会初始化,直到执行到赋值语句。对于const
变量,声明和初始化必须同时进行,因为一旦创建绑定,就不能再改变其值。
- 在底层,JavaScript 引擎在处理模块时,会为每个模块创建一个独立的作用域。
- 模块系统实现:
- TypeScript 的模块系统基于 JavaScript 的模块规范(如 ES6 模块)。在跨模块引用时,模块之间通过导出和导入机制共享变量。当一个模块导入另一个模块的变量时,实际上是创建了对导出变量的引用。
- 对于
let
变量,由于其可重新赋值,这种引用会反映出变量值的变化。而对于const
变量,由于其值不可变,引用始终指向初始值。