1.TypeScript安装
安装
npm install -g typescript
检测ts是否安装成功
tsc -v
第一个ts文件
新建一个文件夹用vscode打开并创建一个ts文件
因为浏览器不支持ts和es6语法,所以需要有一个编译的过程将ts转换成es5语法
设置自动编译
新建一个文件夹testinit并在cmd中进入这个目录并键入tsc --init
命令
在该目录就生成了一个tsconfig.json的文件
修改该配置文件的outDir
部分
我这里报了错
解决办法一:
具体操作为:
右击VSCode快捷键,选择属性,在兼容性模块中选择以管理员身份运行,结束之后重启VSCode,如果不行的话重启一下电脑
然后在终端分别执行如下命令
在终端执行:get-ExecutionPolicy,显示Restricted
在终端执行:set-ExecutionPolicy RemoteSigned
在终端执行:get-ExecutionPolicy,显示RemoteSigned
重新执行之后,js目录自动生成了,每次保存操作都会自动编译代码了。
解决办法二:
直接在cmd控制台执行tsc --watch index.ts
2.数据类型
ts中的数据类型有:
布尔类型(boolean)
数字类型(number)
字符串类型(string)
数组类型(array)
元组类型(tuple)
枚举类型(enum)
任意类型(any)
null 和 undefined
void类型
never类型
布尔类型
// 布尔类型(boolean) true false
var flag:boolean=true
// flag='str'
//- error TS2322: Type 'string' is not assignable to type 'boolean'.
//定义flag的类型之后就不能随意更改类型了,flag只能为true或false
flag=false
es5
var flag = true;
flag = false;
数字类型
// 数字类型(number)
var a:number=123
console.log(a)
es5
var a = 123;
console.log(a);
字符串类型
// 字符串类型(string)
var str:string ='this is ts'
console.log(str)
es5
var str = 'this is ts';
console.log(str);
数组类型
// 数组类型(array)
//es5
var arr=[1,2,'3',4]
//第一种定义方式
let arr:number[]=[1,2,2,3,45]//数组里面只能写数字
let arr2:string[]=['js','ts','node']//数组里面只能是字符串
//第二种定义方式
let arr3:Array<number>=[12,35,64,11]//泛型方式
let arr4:Array<string>=['java','node','js']//泛型方式
es5
//第一种定义方式
let arr = [1, 2, 2, 3, 45]; //数组里面只能写数字
let arr2 = ['js', 'ts', 'node']; //数组里面只能是字符串
//第二种定义方式
let arr3 = [12, 35, 64, 11]; //泛型方式
let arr4 = ['java', 'node', 'js']; //泛型方式
元组类型
// 元组类型(tuple)
let tuplearr:[string,number,boolean]=['js',12,true]//可以指定数组中的元素类型
es5
let tuplearr = ['js', 12, true];
枚举类型
// 枚举类型(enum)
enum Flag{success=1,error=-1}
var f:Flag=Flag.success
console.log(f)
//如果定义枚举时没有赋值那么默认输出枚举值的下标
enum Color{green,blue,red}
var c:Color=Color.red
console.log(c) //2
//如果有如下情况
enum Color2{green,blue=6,red}
var c2:Color2=Color2.green
var c3:Color2=Color2.blue
var c4:Color2=Color2.red
console.log(c2) //0
console.log(c3) //6
console.log(c4) //7
es5
// 枚举类型(enum)
var Flag;
(function (Flag) {
Flag[Flag["success"] = 1] = "success";
Flag[Flag["error"] = -1] = "error";
})(Flag || (Flag = {}));
var f = Flag.success;
console.log(f);
//如果定义枚举时没有赋值那么默认输出枚举值的下标
var Color;
(function (Color) {
Color[Color["green"] = 0] = "green";
Color[Color["blue"] = 1] = "blue";
Color[Color["red"] = 2] = "red";
})(Color || (Color = {}));
var c = Color.red;
console.log(c); //2
//如果有如下情况
var Color2;
(function (Color2) {
Color2[Color2["green"] = 0] = "green";
Color2[Color2["blue"] = 6] = "blue";
Color2[Color2["red"] = 7] = "red";
})(Color2 || (Color2 = {}));
var c2 = Color2.green;
var c3 = Color2.blue;
var c4 = Color2.red;
console.log(c2); //0
console.log(c3); //6
console.log(c4); //7
任意类型
var numone:any=123
numone='str'
numone=true
console.log(numone)
用处
//任意类型的用处
var box=document.getElementById('#box')
box.style.color='red'
// 这里会报错 error TS2531: Object is possibly 'null'.
修改为
var box:any=document.getElementById('#box')
box.style.color='red'
es5
var numone = 123;
numone = 'str';
numone = true;
console.log(numone);
//任意类型的用处
var box = document.getElementById('#box');
box.style.color = 'red';
// error TS2531: Object is possibly 'null'.
null和undefined
// null 和 undefined 其他(never类型)数据类型的子类型
// var numtwo:number
// console.log(numtwo)//输出undefined
var numtwo:undefined
console.log(numtwo)//输出undefined
var numthree:number | null | undefined
numthree=123
console.log(numtwo)//如果定以后没有赋值就输出undefined
// null类型与undefined类似
es5
// null 和 undefined 其他(never类型)数据类型的子类型
// var numtwo:number
// console.log(numtwo)//输出undefined
var numtwo;
console.log(numtwo); //输出undefined
var numthree;
numthree = 123;
console.log(numtwo); //如果定以后没有赋值就输出undefined
// null类型与undefined类似
void类型
// void类型 ts中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值
function run(){
console.log('run...')
}
run()
//表示方法没返回任何类型
function run2():void{
console.log('running...')
}
run2()
// 错误写法
// function run2():undefined{
// console.log('running...')
// }
// run2()
// 正确写法
function run3():number{
return 123
}
run3()
es5
// void类型 ts中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值
function run() {
console.log('run...');
}
run();
//表示方法没返回任何类型
function run2() {
console.log('running...');
}
run2();
// 错误写法
// function run2():undefined{
// console.log('running...')
// }
// run2()
// 正确写法
function run3() {
return 123;
}
run3();
never类型
// never类型 :是其他类型(包括null和undefined)的子类型,代表从不会出现的值
// 这意味着声明never的变量只能被never类型所赋值
var q:undefined
q=undefined
var w:null
w=null
var e:never
// e=123//错误写法
e=(()=>{
throw new Error('异常')
})()
es5
// never类型 :是其他类型(包括null和undefined)的子类型,代表从不会出现的值
// 这意味着声明never的变量只能被never类型所赋值
var q;
q = undefined;
var w;
w = null;
var e;
// e=123//错误写法
e = (() => {
throw new Error('异常');
})();
3.函数
es5中函数定义
// es5中声明函数
function run11(){
return '123'
}
var run22=function(){
return 'run2'
}
ts中函数定义
1.声明函数
// 1.函数声明法
function funrun():string{
return 'funrun'
}
//错误写法
// function funrun2():string{
// return 1233
// }
//2.匿名函数
var funrun3=function():number{
return 123
}
funrun3()
2.ts中定义方法传参
function getInfo(name:string,age:number):string{
return `${name}--${age}`
}
getInfo('胡桃',16)
//匿名函数
var getInfo2=function(name:string,age:number):string{
return `${name}--${age}`
}
getInfo2('甘雨',16)
//没有返回值的函数
function run4():void{
console.log('123456')
}
run4()
3.可选参数
//es5里面方法的实参和形参可以不一样,但ts中必须一样,如果不一样就需要配置可选参数
function getInfo3(name:string,age?:number):string{
if(age){
return `${name}--${age}`
}else{
return `${name}--年龄保密`
}
}
getInfo3('胡桃')//必须在可选参数后面加一个?,不然会报错
//注意:建议将可选参数配置在参数的后面,而不是这样写getInfo3(name?:string,age:number)
4.默认参数
// es5中没法设置默认参数es6和ts中都可以设置默认参数
function getInfo4(name:string,age:number=30):string{
if(age){
return `${name}--${age}`
}else{
return `${name}--年龄保密`
}
}
getInfo4('胡桃')//胡桃--30
getInfo4('胡桃',16)//胡桃--16
5.剩余参数
function sum(a:number,b:number,c:number,d:number):number{
return a+b+c+d
}
sum(1,2,3,4)
// es6中使用扩展运算符...来接收参数
function sum2(...result:number[]):number{
var sum=0;
for(var i=0;i<result.length;i++){
sum+=result[i];
}
return sum;
}
sum2(1,2,3,4)
函数重载
- java中方法的重载:重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况。
- typescript中的重载:通过为同一个函数提供多个函数类型定义来试下多种功能的目的。
//ts为了兼容es5,es6重载的写法和java有区别
// es5中出现同名方法,下面的方法会覆盖上面的方法
function ajax(config){
}
function ajax(config,value){
}
ts中的重载
//ts中的重载
function getUserInfo(name:string):string;
function getUserInfo(age:number):number;
function getUserInfo(str:any):any{
if(typeof str=='string'){
return '我叫:'+str
}else{
return '我的年龄是'+str
}
}
getUserInfo('行秋')//我叫行秋
getUserInfo(16)//我的年龄是16
// getUserInfo(true)//报错
function getUserInfo2(name:string):string;
function getUserInfo2(name:string,age:number):string;
function getUserInfo2(name:any,age?:any):any{
if(age){
return '我叫:'+name+'我的年龄为:'+age
}else{
return '我叫:'+name
}
}
getUserInfo2('七七')//我叫:七七
// getUserInfo2(132)//报错
getUserInfo2('凝光',18)//我叫:凝光我的年龄为:18
箭头函数
// 箭头函数 this指向上下文
setTimeout(function(){
console.log(11)
},1000)
setTimeout(() => {
console.log(11)
}, 1000);
4.类
es5中的类
1.简单的类
// 1.简单的类
function Person(){
this.name='胡桃';
this.age=10;
this.run=function(){//实例方法
console.log('this is class in es5!')
}
}
var p=new Person();
console.log(p.name)//胡桃
p.run()
//原型链增加属性或方法
Person.prototype.sex="女"
Person.prototype.work=function(){
console.log(this.name+"是往生堂堂主!")
}
2.静态方法
//2.类里面的静态方法
Person.getInfo=function(){
console.log('我是静态方法')
}
//调用
Person.getInfo();
3.继承
继承模式:原型链+对象冒充的组合继承模式
//3.es5中的继承
function Son(){
Person.call(this)//对象冒充实现继承
}
var son=new Son();
son.run()
son.work()//报错,无法继承原型链上的属性和方法
//原型链继承:可以继承构造函数里面的属性和方法,也可以继承原型链上的属性和方法
function Son2(){
}
Son2.prototype=new Person()
var s=new Son2();
s.run()
s.work()//两个方法都正常执行
以上继承出现的问题:
function Animal(name,sex){
this.name=name;
this.sex=sex;
this.run=function(){
console.log(this.name+'喜欢吃鱼!')
}
}
function Cat(name,sex){
}
Cat.prototype=new Animal()
var c=new('小花猫','女') //实例化子类无法给父类传参
c.run()//undefined喜欢吃鱼!
//这里的name值拿不到
所以修改为 原型链+对象冒充的组合继承模式
function Animal(name,sex){
this.name=name;
this.sex=sex;
this.run=function(){
console.log(this.name+'喜欢吃鱼!')
}
}
function Cat(name,sex){
Animal.call(this,name,sex) //对象冒充继承 实例化子类可以给父类传参
}
Cat.prototype=new Animal()
var c=new('小花猫','女') //实例化子类无法给父类传参
c.run()//小花猫喜欢吃鱼!
另一种写法:
//另一种写法
function Animal(name,sex){
this.name=name;
this.sex=sex;
this.run=function(){
console.log(this.name+'喜欢吃鱼!')
}
}
function Cat(name,sex){
Animal.call(this,name,sex) //对象冒充继承 实例化子类可以给父类传参
}
Cat.prototype=Animal.prototype
var c=new('小花猫','女') //实例化子类无法给父类传参
c.run()//小花猫喜欢吃鱼!
ts中的类
1.ts中类的定义
//es5
function Person(name){
this.name=name
this.run=function(){
console.log(this.name)
}
}
var p=new Person('胡桃')
p.run();
//ts
class Person{
name:string; //属性 前面省略了public 关键字
constructor(name:string){//构造函数 实例化类的时候触发的方法
this.name=name;
}
run():void{
console.log(this.name)
}
}
var p=new Person('胡桃')
p.run();
class Person{
name:string; //属性 前面省略了public 关键字
constructor(name:string){//构造函数 实例化类的时候触发的方法
this.name=name;
}
run():void{
console.log(this.name)
}
getName():string{
return this.name
}
setName(name:string):void{
this.name=name
}
}
var p=new Person('胡桃')
p.run();
console.log(p.getName())//胡桃
p.setName('七七')
console.log(p.getName())//七七
2.ts中的继承
使用关键字extends super
class Person{
name:string;
constructor(name:string){
this.name=name;
}
run():string{
return `${this.name}在跑步`
}
}
var p=new Person('胡桃')
console.log(p.run())//胡桃在跑步
// 继承
class Son extends Person{
constructor(name:string){
super(name)
}
work(){
console.log(`${this.name}+在工作`)
}
}
var s=new Son('七七')
console.log(s.run())//七七在跑步
s.work()//七七在工作
3.类里面的修饰符
ts里面定义属性的时候给我们提供了三种修饰符
- public 共有 在类里面、子类、类外面都可以访问
- protected 保护类型 在类里面、子类里面可以访问,在类外部没法访问
- private 私有 在类里面可以访问、子类、类外部都没法访问
注意:属性不加修饰符默认为public
//public
class Person{
public name:string;
constructor(name:string){
this.name=name;
}
run():string{
return `${this.name}在跑步`
}
}
var p=new Person('胡桃')
console.log(p.name)//胡桃
//protected
class Person{
protected name:string;
constructor(name:string){
this.name=name;
}
run():string{
return `${this.name}在跑步`
}
}
var p=new Person('胡桃')
console.log(p.name)//报错
//Property 'name' is protected and only accessible within class 'Person' and its subclasses.
//private
class Person{
private name:string;
constructor(name:string){
this.name=name;
}
run():string{
return `${this.name}在跑步`
}
}
var p=new Person('胡桃')
console.log(p.name)//报错
4.静态属性 静态方法
//es5
function Person(){
this.run1=function(){
}
}
Person.name="胡桃"//静态属性
Person.run2=function(){//静态方法
}
var p=new Person()
console.log(Person.name)
Person.run2()//静态方法的调用
//ts
class Person{
public name:string;
static sex='女';
constructor(name:string){
this.name=name;
}
run(){//实例方法
console.log(this.name+'在跑步')
}
work(){
console.log(this.name+'在工作')
}
static print(){//静态方法
console.log('print静态方法!'+this.sex)
}
}
var p =new Person('胡桃')
p.run()
Person.print()//静态方法调用
console.log(Person.sex)
总结:静态方法就是把一个方法当做属性来使用
5.多态
概念:父类定义一个方法不去实现,让继承它的子类去实现,每一个子类有不同的表现。多态是属于继承的。
class Animal{
name:string;
constructor(name:string){
this.name=name;
}
eat(){
console.log('喜欢吃')
}
}
class Cat extends Animal{
constructor(name:string){
super(name)
}
eat() {
return this.name+'吃鱼'
}
}
class Dog extends Animal{
constructor(name:string){
super(name)
}
eat() {
return this.name+'吃骨头'
}
}
6.抽象类
概念:它是提供其他类继承的基类,不能直接被实例化
用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
abstract抽象方法只能放在抽象类里面
抽象类和抽象方法用来定义标准:Animal这个类要求它的子类必须包含eat方法
//标准:
abstract class Animal {
public name:string;
constructor(name:string){
this.name=name;
}
abstract eat():any;
}
class Dog extends Animal{
constructor(name:any){
super(name)
}
//抽象类的子类必须实现抽象类里面的抽象方法,不然会出现报错
eat() {
console.log(this.name+'吃粮食')
}
}
var d=new Dog('小狗狗');
d.eat()
5.接口
接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。
接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。
typescrip中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。
属性接口
属性接口:对json的约束
//ts中定义方法
function printLabel():void{
console.log('printLabel')
}
printLabel()
//ts中传入参数
function printLabel(label:string):void{
console.log('printLabel')
}
printLabel('1234')
//传入json
function printLabel(labelInfo:{name:string}):void{
console.log('printLabel')
}
printLabel('1234')//错误写法
printLabel({label:'胡桃'})//错误写法
printLabel({name:'胡桃'})//正确写法
对批量方法传入参数进行约束
接口:行为和动作的规范,对批量方法进行约束
interface FullName{
firstName:string;
secondName:string;
}
function printName(name:FullName){
//传入对象 firstName secondName
console.log(name.firstName+'--'+name.secondName)
}
printName('1354')//错误写法
var obj={
age:18,
firstName:'胡桃',
secondName:'七七'
}
printName(obj) //正确写法
可选属性接口
interface FullName{
firstName:string;
secondName?:string
}
function getName(name:FullName){
console.log(name)
}
getName({
secondName:'qiqi',
firstName:'hutao'
})
getName({
firstName:'hutao'
})//给接口中的属性加一个?就表示该属性可选
函数类接口
函数类型接口:对方法传入的参数 以及返回值进行约束
//加密的函数类型接口
interface encrypt{
(key:string,value:string):string;
}
var md5:encrypt=function(key:string,value:string):string{
//模拟操作
return key+value;
}
console.log(md5('name','qiqi'))//nameqiqi
可索引接口
可索引接口:数组、对象的约束
//ts定义数组
var array1:number[]=[132,45,1235]
var array2:Array<string>=['123','321']
//对数组的约束
interface UserArr{
[index:number]:string
}
var array:UserArr=['123','321'];
console.log(array[0])//123
// 对对象的约束
interface UserObj{
[index:string]:string
}
var array:UserObj={name:'七七'}
类类型接口
类类型接口:对类的约束 和抽象类有点类似
interface AnimalDog{
name:string;
eatFood(str:string):void;
}
class Doggy implements AnimalDog{
name:string;
constructor(name:string){
this.name=name
}
eatFood(){
console.log(this.name+'吃粮食')
}
}
var doggy=new Doggy('小白');
doggy.eatFood()//小白吃粮食
扩展接口
接口扩展:接口可以继承接口
interface AnimalDog{
eatdog():void;
}
interface Fish extends AnimalDog{
swim():void;
}
class Jinli implements Fish{
public name:string;
constructor(name:string){
this.name=name
}
eatdog(): void {
console.log(this.name+'喜欢吃饲料')
}
swim() {
console.log(this.name+'喜欢游泳')
}
}
var fish=new Jinli('小鲤鱼');
fish.swim()//小鲤鱼喜欢游泳
fish.eatdog()//小鲤鱼喜欢吃饲料
更复杂的
interface AnimalDog{
eatdog():void;
}
interface Fish extends AnimalDog{
swim():void;
}
class BigShark {
public name:string;
constructor(name:string){
this.name=name
}
eating(food:string){
console.log((this.name+food))
}
}
class SmallShark extends BigShark implements Fish{
constructor(name:string){
super(name)
}
eatdog(): void {
console.log(this.name+'喜欢吃饲料')
}
swim() {
console.log(this.name+'喜欢游泳')
}
}
var shark=new SmallShark('小黑');
shark.eating('吃肉肉')//小黑吃肉肉
6.泛型
- 泛型:软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
- 在像c#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。这样用户就可以以自己的数据类型来使用组件。
- 通俗理解:泛型就是解决类接口方法的复用性、以及对不特定数据类型的支持
泛型定义
需求:同时返回string类型和number类型
//只能返回string类型的数据
function getData(value:string):string{
return value
}
// 同时返回string类型和number类型 (代码冗余)
function getData1(value:string):string{
return value
}
function getData2(value:number):number{
return value
}
// 同时返回string类型和number类型 any可以解决,但是放弃了类型检查
function getData(value:any):any{
return value;
}
用泛型来实现需求
// 泛型:可以支持不特定的数据类型 要求:传入的参数和返回的参数一致
function getData<T>(value:T):T{
return value
}
getData<number>(123);
getData<string>('七七');
泛型类
泛型类:有个最小堆算法,需要同时支持返回数字和字符串两种类型。通过泛型类来实现
class MinClass{
public list:number[]=[];
add(num:number){
this.list.push(num)
}
min():number{
var minNum=this.list[0];
for(var i=0;i<this.list.length;i++){
if(minNum>this.list[i]){
minNum=this.list[i]
}
}
return minNum
}
}
var m=new MinClass()
m.add(2)
m.add(21)
m.add(1)
m.add(11)
console.log(m.min())//1 这里只支持传入数字
//类的泛型
class MinClass<T>{
public list:T[]=[];
add(value:T):void{
this.list.push(value)
}
min():T{
var minNum=this.list[0];
for(var i=0;i<this.list.length;i++){
if(minNum>this.list[i]){
minNum=this.list[i]
}
}
return minNum
}
}
var m1 =new MinClass<number>();//实例化类,并且指定了类的T代表的类型是number
m1.add(12)
m1.add(1)
m1.add(14)
console.log(m1.min())//1
var m2 =new MinClass<string>();
m2.add('a')
m2.add('b')
m2.add('d')
console.log(m2.min())//a
泛型接口
// 函数接口
interface ConfigFn{
(value1:string,value2:string):string;
}
var setData:ConfigFn=function (value1:string,value2:string):string{
return value1+value2
}
setData('name','七七')
// 泛型接口
// 第一种
interface ConfigFn{
<T>(value:T):T;
}
var getData:ConfigFn=function<T>(value:T):T{
return value;
}
getData<string>('七七')
// 第二种
interface ConfigFn<T>{
(value:T):T;
}
function getData<T>(value:T):T{
return value;
}
var myGetData:ConfigFn<string>=getData;
myGetData('20')
把类作为参数的泛型
class User{
username:string | undefined;
password:string | undefined
}
class MysqlDb{
add(user:User):boolean{
console.log(user)
return true
}
}
var u=new User();
u.username='七七'
u.password='123456'
var db=new MysqlDb();
db.add(u)
如果这里不是对mysql数据库的账户和密码进行验证,换成对某个商品信息的验证,那么要对源码进行修改,工作量较大
//使用泛型修改
class User{
username:string | undefined;
password:string | undefined
}
//操作数据库的泛型类
class MysqlDb<T>{
add(user:T):boolean{
console.log(user)
return true
}
}
var u=new User();
u.username='七七'
u.password='123456'
var db=new MysqlDb<User>();
db.add(u)
常用封装
interface DBI<T>{
add(info:T):boolean;
update(infp:T,id:number):boolean;
delete(id:number):boolean;
get(id:number):any[];
}
//定义一个操作mysql数据库的类
class MysqlDB<T> implements DBI<T>{
add(info: T): boolean {
throw new Error("Method not implemented.");
}
update(infp: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
throw new Error("Method not implemented.");
}
}
//操作用户表 定义一个User类和数据库表做映射
class Student{
username:string | undefined;
password:string | undefined;
}
var stu =new Student();
stu.username='七七';
stu.password='123456'
var oMysql=new MysqlDB<Student>();
oMysql.add(stu);
7.模块化
该部分和node.js类似
home.ts
export function getData():any[]{
console.log('调用模块getData')
return[
{
title:'xxxxx'
},
{
title:'123456'
}
]
}
function add(){
console.log('add方法被调用!')
}
export default {add}//export default只能使用一次
index.ts
import { getData as get } from "./home";
get();
8.命名空间
namespace A{
export class dog{
...
eat(){}
}
namespace B{
export class dog{
}
}
var d=new A.dog()
d.eat()
//命名空间的使用避免了大规模开发中出现的相同类名
命名空间也可以作为模块导出
9.装饰器
和java中的注解类似
类装饰器
类装饰器:在类声明之前被声明(紧靠着类声明)。装饰器应用于类构造函数,可以用来监视,修改或替换类定义,传入一个参数
类装饰器:普通装饰器(无法传参)
function logClass(params:any){
console.log(params)
//params 就是当前类
params.prototype.apiUrl='动态扩展属性'
params.prototypr.run=function(){
console.log('我是一个run方法!')
}
}
@logClass
class HttpClient{
constructor(){
}
getData(){
}
}
var http:any=new HttpClient()
console.log(http.apiUrl)
http.run()
类装饰器:装饰器工厂(可传参)
function logClass(params:string){
return function(target:any){
console.log(target)
console.log(params)
target.prototype.apiUrl=params
}
}
@logClass('http://www.xxx.com/api')
class HttpClient{
constructor(){
}
getData(){
}
}
var http:any=new HttpClient()
console.log(http.apiUrl)//http://www.xxx.com/api
function logClass(target:any){
console.log(target)
return class extends target{
apiUrl:any="修改后的数据"
getData(){
console.log(this.apiUrl)
}
}
}
@logClass
class HttpClass{
public apiUrl:string |undefined
constructor(){
this.apiUrl='构造函数里面的api'
}
getData(){
console.log(this.apiUrl)
}
}
var http=new HttpClass()
http.getData()//修改后的数据
属性装饰器
属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、成员的名字。
类装饰器
function logClass(params:string){
return function(target:any){
console.log(target)
console.log(params)
target.prototype.apiUrl=params
}
}
//属性装饰器
function logProperty(params:any){
return function(target:any,attr:any){
console.log(target)
console.log(attr)
target[attr]=params
}
}
@logClass('xxx')
class HttpClient{
@logProperty('http://baidu.com')
public url:any |undefined
constructor(){
}
getData(){
console.log(this.url)
}
}
var http=new HttpClient()
http.getData()//http://baidu.com
方法装饰器
它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰会在运行时传入下列3个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。 2、成员的名字。
3、成员的属性描述符。
//方法一
function logMethods(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target)
console.log(methodName)
console.log(desc)
target.apiUrl='xxx'
target.run=function(){
console.log('running!')
}
}
}
class HttpClient{
public url:any |undefined
constructor(){
}
@logMethods('http://baidu.com')
getData(){
console.log(this.url)
}
}
var http:any=new HttpClient()
http.run()
//方法二
function logMethods(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target)
console.log(methodName)
console.log(desc.value)
// 修改装饰器的方法,把装饰器方法里面传入的所有参数改为string类型
// 1.保存当前方法
var oMethod=desc.value
desc.value=function(...args:any[]){
args=args.map((val)=>{
return String(val);
})
console.log(args)
oMethod.apply(this,args)
}
}
}
class HttpClient{
public url:any |undefined
constructor(){
}
@logMethods('http://baidu.com')
getData(){
console.log('aaa')
}
}
var http:any=new HttpClient()
http.getData(123456,'xxx')
//['123456','xxx']
//aaa
方法参数装饰器
…(看不懂了。。)