1、模块的概念
内部模块类似于命名空间,外部模块才简称为模块
模块在自身作用域内起作用,不能在全局作用域中使用(被导出是例外)
模块内的变量,函数,类在模块外不可见,可以通过export导出。然后在其他地方使用import导入
因此
可以把公共功能抽离成一个文件作为模块
模块内的变量,函数,类等默认是私有的,并通过export向外暴露,暴露后通过import导入。
1、创建模块文件db.ts
export let dbURL = 'xxxxx';
//获取数据库数据
export function getData(): any[] {
console.log('获取数据库的数据');
return [
{ title: 'xxtitlexx' },
{ title: 'xxtitlexx' },
];
}
export function save(): void {
console.log('保存数据成功');
}
2、导入并使用模块文件db.ts
index.ts
import { getData,save,dbURL } from './modules/db'
const myarr = getData()
save();
console.log(myarr);
3、在node环境下运行
在浏览器中无法支持,需要在node环境下执行编译后的index.js
node index.js
2、模块的导出
- 在暴露过程中可以集中暴露,直接以对象形式进行暴露,上例模块部分可以写成
let dbURL = 'xxxxx';
//获取数据库数据
function getData(): any[] {
console.log('获取数据库的数据');
return [
{ title: 'xxtitlexx' },
{ title: 'xxtitlexx' },
];
}
function save(): void {
console.log('保存数据成功');
}
export { dbURL,getData,save}
- export的时候也可以使用as关键字,未某个导出的方法或属性起别名
export { dbURL,getData as get,save}
在import的时候则只能使用别名,而不能使用原名称
- 只有一个方法的时候可以使用默认导出export default
export default function myfun(){
}
或
在已经写好方法体的情况下
export default myfun
import myfun from 'xxxxx'
注意,export default在单个模块中只能使用一次
3、使用命名空间
命名空间:内部模块,主要用于组织代码,避免命名冲突
模块:ts的外部模块的简称,侧重代码的复用,一个模块里可能有多个命名空间
大致与java的命名空间一致
命名空间内的变量、函数、类等要使用export导出
namespace A {
export class Dog { }
}
namespace B {
export class Dog {
}
}
let d1 = new A.Dog();
let c1 = new B.Dog();
4、导出、导入命名空间
1、创建命名空间文件db.ts
export namespace A {
export class Dog {
name: string;
constructor(name:string) {
this.name = name;
}
sing() {
console.log(`${this.name} is singing a song`);
}
}
}
export namespace B {
export class Dog {
}
}
2、导入命名空间
import { A,B } from './modules/db'
let d1 = new A.Dog('zhagnsan');
let c1 = new B.Dog();
d1.sing()
5、装饰器
- 装饰器是一种特殊类型的声明,能够被附加到类声明、方法、属性或参数上,可以修改类的行为
- 通俗讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
- 常见的装饰器有:类装饰器、属性装饰器,方法装饰器、参数装饰器
- 装饰器的写法:普通装饰器(无法传参),装饰器工厂(可传参)
- 装饰器是过去几年js最大的成就之一,已是es7的标准特性之类
6、类装饰器
类装饰器在类声明之前被声明(紧靠着类声明)。
类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。传入一个参数
//声明一个装饰器,和函数声明一样
function logClass(params: any) {
console.log(params);//params就是被修饰的类
//给被装饰的类原型进行扩展
params.prototype.apiUrl = 'myapiurl';//扩展了原型,增加了apiUrl属性
params.prototype.run = function () {
console.log('i am a method of running');
}
}
//使用@表示调用装饰器
@logClass
class HttpClient {
constructor(){
}
getData() {
}
}
@logClass
class Person{
constructor() { }
work() { }
}
let p1: any = new Person();
let h1:any = new HttpClient();
console.log(p1.apiUrl, h1.apiUrl);
p1.run();
h1.run();
7、装饰器工厂(可传参)
这里有两个参数,一个是装饰器本身的参数,接收设计者传入的参数,一个是工厂返回的函数参数,接收被装饰类
//声明一个装饰器,和函数声明一样
function logClass(params: any) {
//返回一个函数,这里的target是从被装饰类中返回过来的参数,成为一个装饰器工厂
return function (target: any) {
console.log(params);
console.log(target);
target.prototype.apiUrl = params;
}
}
//使用@表示调用装饰器
@logClass('http://www.sina.com')//表示把hello赋给了装饰器的params,把整个类赋值给了target
class HttpClient {
constructor(){
}
getData() {
}
}
let h1:any = new HttpClient();
console.log(h1.apiUrl);
8、装饰器修改类构造函数
类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明
//声明一个装饰器,和函数声明一样
function logClass(target: any) {
console.log(target);
//返回一个匿名类,并且继承了target类,注意要重载父类的所有属性和方法
return class extends target {
//修改apiUrl,实际是是要
apiUrl: any = '我是修改后的数据';
getData() {
console.log(this.apiUrl+'---');
}
}
}
//使用@表示调用装饰器
@logClass
class HttpClient {
public apiUrl: string | undefined;
constructor(){
this.apiUrl = '我是构造函数里面的apiurl';
}
getData() {
console.log(this.apiUrl);
}
}
let h1:any = new HttpClient();
h1.getData()
9、属性装饰器
属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
2、成员的名字
//声明一个类装饰器,和函数声明一样
function logClass(params: any) {
//返回一个函数,这里的target是从被装饰类中返回过来的参数,成为一个装饰器工厂
return function (target: any) {
target.prototype.apiUrl = params;
}
}
//声明一个属性装饰器
function logProperty(params: any) {
//返回一个函数,要接收两个参数
return function (target: any, attr: any) {
console.log(target);
console.log(attr);
target[attr] = params;
}
}
//使用@表示调用装饰器
@logClass('http://www.sina.com')//表示把hello赋给了装饰器的params,把整个类赋值给了target
class HttpClient {
//使用属性装饰器
@logProperty('http://sohu.com.cn')
public url: any | undefined;
constructor(){
}
getData() {
console.log(this.url);
}
}
let h1 = new HttpClient();
h1.getData()
10、方法装饰方法器(增加类属性及类方法)
会被应用到方法的属性描述符上,可以用来监视、修改或替换方法定义
方法装饰会在运行时传入下列3个参数:
1、对于静态成员来说是类的构造函数,对实例成员是类的原型对象
2、成员的名字
3、成员的属性描述符
//声明一个装饰器
function get(params: any) {
//返回一个函数,要接收两个参数
return function (target: any,methodName:any,desc:any) {
console.log(target);
console.log(methodName);
console.log(desc);
//为方法扩展属性
target.apiUrl = 'http://www.baidu.com';
target.run = function () {
console.log(' my method is run ');
}
}
}
class HttpClient {
public url: any | undefined;
constructor(){
}
//为方法添加自定义的get装饰器
@get('http://www.sina.com')
getData() {
console.log(this.url);
}
}
let h1:any = new HttpClient();
console.log(h1.apiUrl);
h1.run();
11、方法装饰器修改类的方法
//声明一个装饰器
function get(params: any) {
//返回一个函数,要接收两个参数
return function (target: any,methodName:any,desc:any) {
console.log(target);
console.log(methodName);
console.log(desc.value);
//修改被装饰类的方法,把装饰器方法里面传入的所有参数改为string类型
//1、保存当前的方法
let oMethod = desc.value;
desc.value = function (...args:any[]) {
args = args.map((value) => {
return String(value);
})
console.log(args);
oMethod.apply(this, args);
}
}
}
class HttpClient {
public url: any | undefined;
constructor(){
}
//为方法添加自定义的get装饰器
@get('http://www.sina.com')
getData(...args:any[]) {
console.log(args);
console.log('我是getData里面的方法');
}
}
let h1:any = new HttpClient();
h1.getData(123,'xxxx');
12、方法参数装饰器
参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:
1、对于静态成员来说是构造函数,对于实例成员来说是原型对象
2、参数的名字
3、参数在函数参数列表中的索引。
//定义一个方法参数装饰器
function logParams(params: any) {
//返回一个函数,要接收3个参数,target是原型对象,methodName是方法名称,paramsIndex参数索引
return function (target: any,methodName:any,paramsIndex:any) {
console.log(target);
console.log(methodName);
console.log(paramsIndex);
//在装饰器上对原型添加一些数据
target.apiUrl = params;
}
}
class HttpClient {
public url: any | undefined;
constructor(){
}
//在方法的参数中调用装饰器
getData(@logParams('xxxxx') uuid:any) {
console.log(uuid);
}
}
let h1:any = new HttpClient();
h1.getData(123456);
console.log(h1.apiUrl);
13、装饰器的执行顺序
属性>方法>方法参数>类装饰器
如果有同样的装饰器,则先执行后面的。