TS模块化规范与命名空间

模块化规范:

AMD、CMD、CommonJS、ES Module

TS模块化规范与命名空间_第1张图片

CommonJS规范主要是为了弥补JavaScript没有标准的缺陷,已达到像Python、Ruby和Java那样具备开发大型应用的基础能力,而不是停留在开发浏览器端小脚本程序的阶段。使用CommonJS规范进行开发,需要依赖Node.js环境。(例如浏览器不兼容CommonJS的根本原因,在于缺少四个Node.js环境的变量:module、exports、require、global)

AMD规范(异步模块定义)是 RequireJS 在推广过程中对模块定义的规范化产出,不是JavaScript原生支持。使用AMD规范进行开发时,需要引入RequireJS这个第三方函数库,通过define()来定义模块,采用require()语句来加载模块。

CMD(通用模块定义)是 SeaJS 在推广过程中对模块定义的规范化产出。使用CMD规范进行开发时,需要引入SeaJS这个第三方函数库。在CMD规范中,一个模块就是一个文件,使用define()语句定义模块,使用seajs.use()加载模块。

三者的区别:

CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。

AMD是异步加载模块,核心是预加载,先对依赖的全部文件进行加载,加载完了再进行处理。

CMD也是异步加载模块,是按需加载。AMD和CMD最大的区别是对依赖模块的执行时机不同,而不是加载时机不同,二者皆为异步加载模块。

AMD是前置依赖,在定义模块的时候就要声明其依赖的模块;

CMD是就近依赖,只有在用到某个模块的时候再去require;
TS模块化规范与命名空间_第2张图片

模块(关键字module)

“内部模块”现在称作“命名空间”,“外部模块”现在简称为“模块”;

内部外部为一个相对概念,在ES6和Nodejs中,引入了模块的概念,即一个文件就是一个模块;“内部模块”即当前文件内的模块,“外部模块”即当前文件外的其他模块;

在这里插入图片描述

例如我们在TS工程下新建一个ts文件声明一个变量a,在另一个文件同样声明一个变量a,这时候会出现错误信息:

原因:因为该文件内容是对全局可见的;
解决方案:只需要通过import || export引入模块系统即可;

ES6:(TS也适用)
导出模块:export;(默认导出 export default)
导入模块:import;

CommonJS和AMD:
导出模块:module.exports 或 exports;
导入模块:require( );

注意:

1、module.exports的初始值是一个空对象;TS模块化规范与命名空间_第3张图片
2、exports是指向module.exports的引用(exports只是对module.exports的一个全局引用);
在这里插入图片描述
在 Node 中,不能用任何其他对象、函数或变量给 exports 赋值。
例如:
//错误写法 class Currency { } exports = Currency
需要将 exports 换成 module.exports。用 module.exports 可以对外提供单个变量、函数或者对象。
例如
//正确写法 class Currency { } modules.exports = Currency

3、require( )返回的是modul.exports而不是exports;
如果你创建了一个既有 exports 又有 module.exports 的模块,那它会返回 module.exports,而 exports 会被忽略。
module.exports才是真正的接口,exports只不过是它的一个辅助工具。 最终返回给调用的是module.exports而不是exports。
所有的exports收集到的属性和方法,都赋值给了Module.exports。当然,这有个前提,就是module.exports本身不具备任何属性和方法。
如果,module.exports已经具备一些属性和方法,那么exports收集来的信息将被忽略。
TS模块化规范与命名空间_第4张图片
TS模块化规范与命名空间_第5张图片

为了支持CommomJS和AMD的exports,TS提供了export=语法:
TS模块化规范与命名空间_第6张图片

动态模块加载(模块只在被需要时加载):

在这里插入图片描述
TS模块化规范与命名空间_第7张图片

外部模块的声明:

在开发过程中我们有时需要引用其他第三方的 JavaScript 的库,虽然通过直接引用可以调用库的类和方法,但是却无法使用TypeScript 诸如类型检查等特性功能。为了解决这个问题,需要将这些库里的函数和方法体的具体实现方法删除后,只保留导出类型声明。我们将所有的这些第三方库的类型声明存放在声明文件中,声明文件以.d.ts为后缀。

例如:
TS模块化规范与命名空间_第8张图片

使用重新导出进行扩展:

TS模块化规范与命名空间_第9张图片

命名空间(关键字namespace)

“内部模块”现在称做“命名空间”;
使用关键字“namespace”,使用export让命名空间里的接口和类暴露出去,不暴露在命名空间外则访问不到。
TS模块化规范与命名空间_第10张图片

命名空间可以分割成多个文件,它们仍属于同一个命名空间,但需要我们加入引用标签(三斜线指令)来告诉编译器文件之间的关联。

编译器会对输入文件进行预处理来解析所有三斜线引用指令,这个过程会以一些根文件开始,它们是在命令行中指定的文件或是在tsconfig.json中的“files”列表里的文件。这些根文件按指定的顺序进行预处理,在一个文件被加入列表前,它包含的所有三斜线引用都要被处理,三斜线引用以它们在文件里出现的顺序,使用深度优先的方式解析。

使用tsc编译时,编译器也会根据代码里引用标签的顺序自动地对输出进行排序。

但使用webpack打包编译ts文件,无法识别三斜线指令,必须使用export与import来导出导入命名空间;

命名空间别名

import q = x.y.z

命名空间和模块

使用命名空间

好处:
结合三斜线指令,使用tsc进行编译,并通过 --outFile将多个文件的同个命名空间结合在一起,再将编译且结合后的js文件通过

缺陷:
在大型应用中,很难去识别组件之间的依赖关系。

命名空间和模块的陷阱:

1、不要使用三斜线指令来引用模块;
TS模块化规范与命名空间_第11张图片

2、不应该对模块使用命名空间

使用命名空间的目的是为了能够将逻辑分组和避免命名上的冲突,模块文件本身已经就是一个逻辑的分组,而且使用模块时的名字也是由导入的时候决定的,所以完全没必要在模块中为导出的对象增加额外的模块层。

不好的例子:
TS模块化规范与命名空间_第12张图片

改进的例子:
TS模块化规范与命名空间_第13张图片

你可能感兴趣的:(typescript)