21. TypeScript 命名空间-Namespace
以前的教程都是通过Node
来运行代码的,这节为了有更好的演示效果,我们要在浏览器中运行代码。这就要求我们重新创建一个项目,直接在桌面上建立一个文件夹TSWeb
。
搭建浏览器开发环境步骤
如何搭建一个最基础的 TS 开发环境了:
- 建立好文件夹后,打开 VSCode,把文件夹拉到编辑器当中,然后打开终端,运行
npm init -y
,创建package.json
文件。 - 生成文件后,我们接着在终端中运行
tsc -init
,生成tsconfig.json
文件。 - 新建
src
和build
文件夹,再建一个index.html
文件。 - 在
src
目录下,新建一个page.ts
文件,这就是我们要编写的ts
文件了。 - 配置
tsconfig.json
文件,设置outDir
和rootDir
(在 15 行左右),也就是设置需要编译的文件目录,和编译好的文件目录。 - 然后编写
index.html
,引入<script src="./build/page.js"></script>
,当让我们现在还没有page.js
文件。 - 编写
page.ts
文件,加入一句输出console.log('mybj123.com')
,再在控制台输入tsc
,就会生成page.js
文件 - 再到浏览器中查看
index.html
文件,如果按F12
可以看到mybj123.com
,说明我们的搭建正常了。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="./build/page.js"></script> <title>Document</title> </head> <body></body> </html>
这就是你开发最基础的前端项目时需要作的环境配置。我觉的学习这东西,学会了就要用,如果不用你很快就会忘记。所以以后你在做项目,请尽量使用TypeScript
来进行编写。
没有命名空间时的问题
为了你更好的理解,先写一下这样代码,用类的形式在index.html
中实现header
,content
和Footer
部分,类似我们常说的模板。
在page.ts
文件里,写出下面的代码:
class Header { constructor() { const elem = document.createElement("div"); elem.innerText = "This is Header"; document.body.appendChild(elem); } } class Content { constructor() { const elem = document.createElement("div"); elem.innerText = "This is Content"; document.body.appendChild(elem); } } class Footer { constructor() { const elem = document.createElement("div"); elem.innerText = "This is Footer"; document.body.appendChild(elem); } } class Page { constructor() { new Header(); new Content(); new Footer(); } }
写完后我们用tsc
进行编译一次,然后修改index.html
文件,在<body>
标签里引入<script>
标签,并实例化Page
,代码如下:
<body> <script>new Page();</script> </body>
这时候再到浏览器进行预览,就可以看到对应的页面被展现出来了。看起来没有什么问题,但是有经验的程序员就会发现,这样写全部都是全局变量(通过查看./build/page.js
文件可以看出全部都是var
声明的变量)。过多的全局变量会让我们代码变的不可维护。
这时候你在浏览器的控制台(Console
)中,分别输入Header
、Content
、Footer
和Page
都时可以拿到对应的变量的,说明他们全都是全局变量。
其实你理想的是,只要有Page
这个全局变量就足够了,剩下的可以模块化封装起来,不暴露到全局。
命名空间的使用
命名空间
这个语法,很类似编程中常说的模块化思想,比如webpack
打包时,每个模块有自己的环境,不会污染其他模块,不会有全局变量产生。命名空间就跟这个很类似,注意这里是类似,而不是相同。
命名空间声明的关键词是namespace
,比如声明一个namespace Home
,需要暴露出去的类,可以使用export
关键词,这样只有暴漏出去的类是全局的,其他的不会再生成全局污染了。修改后的代码如下:
namespace Home { class Header { constructor() { const elem = document.createElement("div"); elem.innerText = "This is Header"; document.body.appendChild(elem); } } class Content { constructor() { const elem = document.createElement("div"); elem.innerText = "This is Content"; document.body.appendChild(elem); } } class Footer { constructor() { const elem = document.createElement("div"); elem.innerText = "This is Footer"; document.body.appendChild(elem); } } export class Page { constructor() { new Header(); new Content(); new Footer(); } } }
TS 代码写完后,再到index.html
文件中进行修改,用命名空间的形式进行调用,就可以正常了。 写完后,记得用tsc
编译一下,当然你也可以使用tsc -w
进行监视了,只要有改变就会进行重新编译。
new Home.Page();
现在再到浏览器中进行查看,可以看到现在就只有Home.Page
是在控制台可以得到的,其他的Home.Header
…这些都是得不到的,说明只有Home.Page
是全局的,其他的都是模块化私有的。
这就是 TypeScript 给我们提供的类似模块化开发的语法,它的好处就是让全局变量减少了很多,实现了基本的封装,减少了全局变量的污染。
接下来我们再深入学习命名空间-Namespace。
用命名空间实现组件化
上节的代码虽实现了模块化和全局变量的污染,但是我们工作中分的要更细致一些,会单独写一个components
的文件,然后进行组件化。
在src
目录下新建一个文件components.ts
,编写代码如下:
namespace Components { export class Header { constructor() { const elem = document.createElement("div"); elem.innerText = "This is Header"; document.body.appendChild(elem); } } export class Content { constructor() { const elem = document.createElement("div"); elem.innerText = "This is Content"; document.body.appendChild(elem); } } export class Footer { constructor() { const elem = document.createElement("div"); elem.innerText = "This is Footer"; document.body.appendChild(elem); } } }
这里需要注意的是,我每个类(class
)都使用了export
导出,导出后就可以在page.ts
中使用这些组件了。比如这样使用,代码如下。
namespace Home { export class Page { constructor() { new Components.Header(); new Components.Content(); new Components.Footer(); } } }
这时候你可以使用tsc
进行重新编译,但在预览时,你会发现还是会报错,找不到Components
,想解决这个问题,我们必须要在index.html
里进行引入components.js
文件。
<script src="./build/page.js"></script> <script src="./build/components.js"></script>
这样才可以正常的出现效果。但这样引入太麻烦了,可不可以像webpack
一样,只生成一个文件呢?那答案是肯定的。
多文件编译成一个文件
直接打开tsconfig.json
文件,然后找到outFile
配置项,这个就是用来生成一个文件的设置,但是如果设置了它,就不再支持"module":"commonjs"
设置了,我们需要把它改成"module":"amd"
,然后在去掉对应的outFile
注释,设置成下面的样子。
{ "outFile": "./build/page.js" }
配置好后,删除掉build
下的js
文件,然后用tsc
进行再次编译。
然后删掉index.html
文件中的component.js
,在浏览器里还是可以正常运行的。
子命名空间
也就是说在命名空间里,再写一个命名空间,比如在Components.ts
文件下修改代码如下。
namespace Components { export namespace SubComponents { export class Test {} } //someting ... }
写完后在控制台再次编辑tsc
,然后你在浏览器中也是可以查到这个命名空间的Components.SubComponents.Test
(需要刷新页面后才会显示)。
总结
以上就是今天我们要学的 TypeScript 命名空间的内容,基本讲完了,在工作中如果遇到,这些知识已经完全够用,所以这部分内容就先到这里了。
码云笔记 » 21. TypeScript 命名空间-Namespace