没有命名空间时的问题
先写一下这样代码,用类的形式在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>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 给我们提供的类似模块化开发的语法,它的好处就是让全局变量减少了很多,实现了基本的封装,减少了全局变量的污染。
用命名空间实现组件化
上面的代码虽实现了模块化和全局变量的污染,但是我们工作中分的要更细致一些,会单独写一个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
(需要刷新页面后才会显示)。
学习视频
https://www.bilibili.com/video/BV1qV41167VD?p=22
学习资料
https://jspang.com/detailed?id=63#toc377