在 JS 中命名空间可以有效的避免全局污染,但是 ES6 引入模块系统之后,就很少被提及了。TS 也实现了这个特性,尽管在模块系统中,我们不需要考虑全局污染问题,但是要使用一些全局的类库,命名空间依然是一种比较好的解决方案。
命名空间使用 namespace 关键字声明:
namespace Shape {
let a = 1; // 只在命名空间内可用
export let b = 2; // 导出到全局
}
命名空间还可以进行拆分:
namespace Shape {
let a = 1; // 只在命名空间内可用
export let b = 2; // 导出到全局
export function circle(r:number) {
return Math.PI * r * r;
}
}
namespace Shape {
export function square(x: number) {
return x * x;
}
}
Shape.b;
Shape.circle(1);
Shape.square(1);
只要名称相同,就会合并到一个全局变量中。
命名空间应该在全局环境下使用,不要在模块中使用。
命名空间编译之后的代码是一个 IIFE
(function (Shape) {
var a = 1; // 只在命名空间内可用
Shape.b = 2; // 导出到全局
function circle(r) {
return Math.PI * r * r;
}
Shape.circle = circle;
})(Shape || (Shape = {}));
当我们把命名空间拆分为两个文件时,在一个文件中使用了另一个文件中命名空间抛出的方法:
// a.ts
namespace Shape {
let a = 1; // 只在命名空间内可用
export let b = 2; // 导出到全局
export function circle(r:number) {
return Math.PI * r * r;
}
}
// b.ts
namespace Shape {
export function square(x: number) {
return x * x;
}
}
Shape.b;
Shape.circle(1);
Shape.square(1);
编译 b.ts 时会报错,此时在 b.ts 中需要使用 /// 语法进行引用才能编译:
/// <reference path="a.ts" />
此时编译之后,a 和 b 都会被编译出来