TypeScript 从入门到放弃(三):模块、命名空间、声明合并、声明文件
TypeScript 从入门到放弃(三):模块、命名空间、声明合并、声明文件
镇长前言
本文作为学习笔记,文中内容大多来自官方文档和一些资料,摘抄的部分会在文中标注出原文地址,可以直接参考原文。
前两篇学习了 TS 中基本类型、函数、类、接口、泛型以及高级类型概念和使用方法。这些是基础知识点,虽然简单但是很重要。本文将复习 JS 中的模块对比不同方式模块的区别;如何使用命名空间隔离代码;声明合并的规则等。
模块
在 ES6 之前采用的模块加载方案,主要有 CommonJS
和 AMD
两种。前者用于服务器,后者用于浏览器。ES6 在此基础上实现了模块的功能,使用简单可以完全取代之前的方案,成为浏览器和服务器通用的模块解决方案。
下面学习 ES6 中模块的导出和导入。
导出
ES6 提供了多种导出方式,例如:单独导出,批量导出、导出接口/函数、导出起别名、默认导出以及复合导出等。
导出使用 export
命令,举个例子:
1 | // a.js |
导入
对应着 export
命令,导入使用 import
命令。
1 | // 导入 |
关于 ES6 模块可以参考:阮一峰老师《ES6入门》
浏览器加载
默认情况下,浏览器是同步加载 JS 脚本,遇到 <script>
标签会等待执行完脚本才会继续渲染。在文件较大下载和执行时间较长时,会出现浏览器假死无响应。为了解决这个问题,加入异步加载语法。在 <script>
中使用defer
和async
属性,指定脚本异步加载。
defer
: 渲染完在执行。要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行。async
: 下载完就执行。一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。
在浏览器中加载模块需要将 type
指定为 module
。
1 | <script type="module" src="a.js"/> |
指定 type="module"
的 <script>
都是异步的。
ES6 模块和 CommonJS 模块的区别
ES6
模块和 CommonJS
是完全不同的。
CommonJS
模块输出的是一个值的拷贝,ES6
模块输出的是值的引用。CommonJS
模块是运行时加载的,ES6
模块时编译时输出接口。
拷贝值和值引用的最大区别是:值拷贝时原始值改变拷贝值不会变,值引用则会随原始值改变。
举个例子:
1 | // b.js |
上面的例子输出结果是多少?
b.js
是一个模块导出一个变量 counter
和一个函数 incCounter
。
首次输出 counter
值为 3。当调用 b.incCounter
函数后再输出 counter
仍为 3。导致 counter
不改变的原因 CommonJS
模块是值拷贝。
同样的例子在 ES6 模块中就不会出现这个问题。
1 | // a.js |
以上是 ES6 模块和 CommonJS 模块的区别。具体可以参考阮一峰老师《ES6入门-模块加载》
TS 中模块
为了支持 CommonJS
的 exports
, TS 提供了 export=
语法。export=
语法定义一个模块的导出对象。 这里的对象一词指的是类,接口,命名空间,函数或枚举。若使用export=
导出一个模块,则必须使用 TS 的特定语法import module = require("module")
来导入此模块。
命名空间
命名空间用来解决重名问题,定义命名空间使用 namespace
关键字。
1 | namespace Shape { |
定义了一个 Shape
命名空间,向外部提供了一个 Square
函数,使用 export
关键字导出。调用的方法是 Shape.square(1)
直接使用命名空间调用。
引入命名空间的方法比较特殊,格式如下:
1 | /// <reference path="shape.ts"/> |
使用 ///
引用命名空间。
声明合并
声明合并是指编译器将同名的独立声明合并为单个声明。合并后的声明拥有原来多个声明的特性。
接口的声明合并
1 | interface A { |
两个地方声明同样的接口时,编译器会自动合并到一起。当相同属性类型不同是会提示错误。
命名空间的声明合并
1 | namespace Animals { |
命名空间合并的是导出成员,非导出成员是无法被合并访问的。
函数与命名空间合并
1 | // 命名空间和函数的合并 |
可以使用函数和命名空间合并的方式,为函数添加属性。
注意:函数的声明必须在命名空间前。
类与命名空间合并
1 | // 命名空间和类合并 |
使用合并为类添加一些静态的属性。
注意:类的定义必须在命名空间前。
枚举与命名空间合并
1 | // 命名空间和枚举合并 |
注意:和类与函数不同,枚举可以放在命名空间的后面。
声明文件
当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
声明文件通过 declare
关键字告诉 TS,正在表述其他地方已经存在的代码。
小结
以上是本篇的全部内容,都是一些比较基础的知识点,后续随着学习的深入在慢慢补充。