面试题答案
一键面试主要区别
- 作用域
- 命名空间:内部成员在命名空间内具有全局作用域的特性,只要在命名空间内部,无需额外导入即可访问。不同命名空间之间通过名称来区分,防止命名冲突。例如:
namespace Utils {
export function add(a: number, b: number) {
return a + b;
}
}
// 在同一个文件内可以直接使用Utils.add
let result = Utils.add(1, 2);
- **模块**:每个模块都有自己独立的作用域,模块内部的变量、函数、类等默认是私有的,只有通过 `export` 关键字导出后,其他模块才能通过 `import` 导入使用。例如:
// utils.ts
export function add(a: number, b: number) {
return a + b;
}
// main.ts
import { add } from './utils';
let result = add(1, 2);
- 文件结构与依赖管理
- 命名空间:通常用于在单个文件中组织代码,避免命名冲突。多个命名空间可以合并,例如:
namespace Utils {
export function add(a: number, b: number) {
return a + b;
}
}
namespace Utils {
export function subtract(a: number, b: number) {
return a - b;
}
}
// 现在Utils既有add也有subtract方法
let addResult = Utils.add(1, 2);
let subtractResult = Utils.subtract(3, 1);
- **模块**:更适合大型项目,每个模块是一个独立的文件,通过导入导出明确依赖关系。模块系统有助于更好地管理项目的依赖和代码结构。例如,一个复杂的前端项目可能有多个模块文件,如 `user.ts`、`product.ts` 等,每个模块通过导入和导出与其他模块交互。
3. 编译输出
- 命名空间:编译后会生成一个自执行函数包裹的代码块,多个命名空间可能会合并到同一个作用域中。例如,上述 Utils
命名空间编译后可能类似这样:
var Utils;
(function (Utils) {
function add(a, b) {
return a + b;
}
Utils.add = add;
})(Utils || (Utils = {}));
- **模块**:编译后根据不同的模块规范(如CommonJS、ES6 Modules等)生成不同的代码结构。以ES6 Modules为例,编译后代码会保留导入导出的结构,例如:
// utils.js
export function add(a, b) {
return a + b;
}
// main.js
import { add } from './utils.js';
let result = add(1, 2);
适用场景
- 适合使用命名空间的场景
- 小型项目或简单脚本:例如一个小型的HTML页面交互脚本,不需要复杂的模块依赖管理,只是简单地组织代码避免变量命名冲突。比如一个简单的图片轮播脚本,所有相关的函数和变量可以放在一个命名空间内:
namespace Carousel {
let currentIndex = 0;
let images: HTMLImageElement[] = [];
export function init() {
// 初始化图片轮播的逻辑
images = document.querySelectorAll('img.carousel-img');
}
export function next() {
// 切换到下一张图片的逻辑
currentIndex = (currentIndex + 1) % images.length;
images.forEach((img, index) => {
if (index === currentIndex) {
img.style.display = 'block';
} else {
img.style.display = 'none';
}
});
}
}
// 在HTML页面中直接调用Carousel.init()和Carousel.next()
- **临时性的代码组织**:在开发过程中,临时将一些相关代码组织在一起,后续可能会进一步重构为模块。例如在开发一个新功能时,先将一些辅助函数放在命名空间中,方便开发和测试。
2. 适合使用模块的场景 - 大型前端应用:如单页应用(SPA),涉及到复杂的组件、服务和数据交互,需要清晰的依赖管理和代码结构。例如在一个电商应用中,用户模块、商品模块、购物车模块等都可以作为独立的模块,通过导入导出实现相互通信。
// user.ts
export class User {
constructor(public name: string, public age: number) {}
login() {
console.log(`${this.name} logged in`);
}
}
// main.ts
import { User } from './user';
let user = new User('John', 25);
user.login();
- **可复用的库开发**:如果要开发一个供其他项目复用的前端库,模块可以更好地封装代码,控制接口暴露,方便其他开发者导入和使用。例如开发一个图表绘制库,每个功能模块(如柱状图、折线图等)可以作为独立模块导出。