面试题答案
一键面试编译原理不同
- 命名空间:在编译时,TypeScript命名空间会被编译成JavaScript的立即执行函数(IIFE)。多个命名空间在同一个文件内或不同文件但通过
/// <reference path="..." />
指令关联时,会合并到同一个全局作用域下。例如:
namespace MyNamespace {
export const value = 42;
}
编译后:
var MyNamespace;
(function (MyNamespace) {
MyNamespace.value = 42;
})(MyNamespace || (MyNamespace = {}));
- 模块:模块在编译时,每个模块都被视为一个独立的作用域。TypeScript模块编译后,会根据目标模块系统(如CommonJS、ES6模块等)生成相应的代码。以CommonJS为例:
export const value = 42;
编译后:
exports.value = 42;
运行时机制不同
- 命名空间:由于命名空间最终合并到全局作用域,其变量和函数在运行时存在于全局环境中。这可能会导致命名冲突,特别是在大型项目中。不同命名空间内的代码可以直接访问全局变量,只要这些变量在全局作用域内定义。
- 模块:模块有自己独立的作用域,模块内定义的变量、函数和类默认在外部不可见。只有通过
export
关键字导出的内容才能被其他模块导入使用。模块之间通过导入导出机制进行交互,每个模块在运行时都是一个独立的单元,避免了命名冲突。
命名空间与模块的相互引用和数据交互
- 命名空间引用模块:
- 在命名空间中,如果要引用模块,首先要确保模块已经被正确导入。假设我们有一个模块
module.ts
:
- 在命名空间中,如果要引用模块,首先要确保模块已经被正确导入。假设我们有一个模块
// module.ts
export const moduleValue = 100;
- 然后在命名空间所在文件中,使用
import
导入模块,并在命名空间内使用导入的内容:
import { moduleValue } from './module';
namespace MyNamespace {
export function printModuleValue() {
console.log(moduleValue);
}
}
- 模块引用命名空间:
- 先定义命名空间,假设在
namespace.ts
中:
- 先定义命名空间,假设在
// namespace.ts
namespace MyNamespace {
export const namespaceValue = 200;
}
- 在模块中,要引用命名空间,需要通过
/// <reference path="namespace.ts" />
指令先引入命名空间定义,然后就可以使用命名空间内的导出内容:
/// <reference path="namespace.ts" />
export function printNamespaceValue() {
console.log(MyNamespace.namespaceValue);
}
- 数据交互:无论是命名空间引用模块还是模块引用命名空间,数据交互都是基于导出和导入机制。命名空间通过
export
导出内容,模块通过import
导入;模块通过export
导出,命名空间内导入后使用。这样就可以在两者之间传递数据。