# Typescript 笔记
# 一、安装 编译
在使用 npm 命令前电脑必须得安装 nodejs
安装
npm install -g typescript
或者
cnpm install -g typescript
或者
yarn global add typescript
注意 如果电脑上没有安装过 cnpm,请先安装 cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
注意 如果电脑上没有安装过 yarn,请先安装 yarn
npm install -g yarn
或者
cnpm install -g yarn
运行
tsc filename.ts
自动转译
tsc --init
生成 tsconfig.json 配置文件,修改配置
"outDir":"./js" | |
//js 生成目录 |
vscode 需要点击选项卡的 “终端”,点击 “运行任务”,点击监视所需要监视的 ts 文件夹或者项目即可。
# 二、数据类型
typescript 为了使编写的代码更加规范,更有利于维护
# 1、布尔类型 (boolean)
var flag:boolean = true; | |
flag = false; |
# 2、数字类型 (number)
数字类型包括整型和浮点型
var a:number = 123; | |
a="string"; // 错误写法 | |
a = 3; // 正确写法 |
# 3、字符串类型 (string)
var str:string = 'hello world'; | |
str = 'hello typescript'; // 正确写法 |
# 4、数组类型 (array)
typescript 中有多种定义数组的方法
// 第一种定义数组的方式 | |
var arr:number[] = [1,2,3,4]; | |
var str:string[] = ['php','js','golang']; | |
// 第二种定义数组的方法 PS:vue 似乎不支持泛型 | |
let arr:Array<number> = [1,2,3,4,5]; | |
let str:Array<string> = ['php','js','golang']; | |
// 第三种 | |
var arr:any[] = ['ts',123,true]; | |
console.log(arr); //['ts',123,true]; |
# 5、元组类型 (tuple)
属于数组的一种,可以指定每一个元素的数据类型
let arr:[string,number,boolean] = ['ts','3.14',true]; |
# 6、枚举类型 (enum)
enum Flag{ | |
success=1, // 标识符 [= 整型常数] | |
error=-1 | |
} | |
var f:Flag = Flag.success; | |
console.log(f); //1 | |
console.log(Flag.error); //-1 | |
enum Color{ | |
red,blue = 5,orange | |
} | |
var c:Color = Color.red; | |
console.log(c); //0 如果没有写整型常数,默认下标 | |
console.log(Color.orange); //6 从最近的有值的开始放后推 |
# 7、任意类型 (any)
相当于 js 原来的样子 适用于类型会经常变化的任意类型或者不属于常用数据类型的类型
var num:any = 123; | |
num = 'str'; | |
console.log(num); //str |
# 8、null 和 undefined
其他类型 (never) 的字类型
var num:number; | |
console.log(num); //undefined 报错 | |
var num:undefined; | |
console.log(num); //undefined 正确 | |
var num:number|undefined; | |
console.log(num); //undefined 正确 | |
num = 123; | |
console.log(123); //123 | |
// 定义未赋值就是 undefined |
var num:null; | |
num = null; | |
// 一个元素可能是 number 可能是 null,可能是 undefined | |
var num:number | null | undefined; | |
num = 1234; | |
console.log(num); //1234 |
# 9、void 类型
typescript 中的 void 表示没有任何类型,一般用于定义方法的时候没有返回值
function run():void{// 表示方法没有返回任何类型 | |
console.log('run'); | |
} |
# 10、never 类型
是其他类型 (包括 null 和 undefined) 的字类型,代表从不会出现的值
这意味着声明 never 的变量只能被 never 类型所赋值
var a:never; | |
a = 123; // 错误的写法 | |
let a:never; | |
a=(()=>{ | |
throw new Error('错误'); | |
}) |
# 三、函数
# 1、函数的定义
以前 es5
function run(){ | |
return 'run'; | |
} | |
// 匿名函数 | |
let run = function(){ | |
return 'run'; | |
} |
typescript
function run():string{ | |
return 'run'; | |
} | |
// 匿名函数 | |
let run = function():string{ | |
return 'run'; | |
} |
传参
function getInfo(name:string,age:number):string{ | |
return `${name} ---- ${age}`; | |
} | |
console.log(getInfo('张三',21)); | |
var getInfo = function(name:string,age:number):string{ | |
return `${name} --- ${age}`; | |
} | |
var getInfo = function(name:string,age:number):void{ | |
console.log(name,age); | |
} |
# 2、可选参数
es5 里方法的实参和形参可以不一样,但是 ts 中必须一样,如果不一样就需要配置可选参数
function getInfo(name:string,age?:number):string{ | |
if(age){ | |
return `${name} --- ${age}`; | |
}else{ | |
return `${name} --- 年龄保密`; | |
} | |
} |
可选参数必须是形参最后面
# 3、默认参数
function getInfo(name:string,age:number=20):string{ | |
return `${name} --- ${age}`; | |
} | |
console.log(getInfo('张三')); // 张三 --- 20 |
# 4、剩余参数
function sum(a:number,b:number,c:number,d:number):number{ | |
return a+b+c+d; | |
} | |
let num = sum(1,2,3,4); | |
console.log(num); //10 | |
function sum(...result:number[]):number{ | |
let sum = 0; | |
for(let i = 0;i < result.length;i++){ | |
sum += result[i]; | |
} | |
return sum; | |
} | |
let num = sum(1,2,3,4); | |
console.log(num); //10 |
function sum(a:number,...result:number[]):number{
var sum = a;
for(let i = 0;i < result.length;i++){
sum += result[i];
}
return sum;
}
console.log(sum(1,2,3,4,5,6,7));
# 5、函数重载
通过为同一个函数提供多个函数类型定义来试下多种功能的目的
function getInfo(name:string):string{ | |
} | |
function getInfo(age:number):string{ | |
} | |
function getInfo(str:any):any{ | |
if(typeof str === 'string'){ | |
return '我叫' + str; | |
}else{ | |
return '我的年龄是' + str; | |
} | |
} | |
console.log(getInfo('张三'));// 我叫张三 | |
console.log(getInfo(21));// 我的年龄是 21 |
# 6、箭头函数
setTimeOut(()=>{ | |
},500); |
# 四、类
# 1、es5 中的类
# 1.1 定义类
es5 里的类就是构造函数
function Person(){ | |
this.name = '张三'; | |
this.age = 20; | |
} | |
var p = new Person(); | |
console.log(p.name); // 张三 |
构造函数里增加方法
function Person(){ | |
this.name = '张三'; | |
this.age = 20; | |
this.run = function(){ | |
console.log(this.name + '在运动'); | |
} | |
} | |
var p = new Person(); | |
// 原型链上的属性会被多个实例共享,但是构造函数不会 | |
Person.prototype.sex = '男'; | |
Person.prototype.work = function(){ | |
console.log(this.name + '在工作'); | |
} | |
console.log(p.name); // 张三 | |
p.run(); // 张三在运动 | |
p.work(); // 张三在工作 |
类里的静态方法
function Person(){ | |
this.name = '张三'; | |
this.age = 20; | |
this.run = function(){ | |
console.log(this.name + '在运动'); | |
} | |
} | |
// 静态方法 | |
Person.getInfo = function(){ | |
console.log('我是静态方法'); | |
} | |
// 通过 new 实例才能调用的方法不是静态方法 | |
var p = new Person(); | |
// 调用静态方法 | |
Person.getInfo(); |
# 1.2 继承
es5 里的继承
// 对象冒充继承 ------------------------- | |
function Person(){ | |
this.name = '张三'; | |
this.age = 20; | |
this.run = function(){ | |
console.log(this.name + '在运动'); | |
} | |
} | |
Person.prototype.sex = '男'; | |
Person.prototype.work = function(){ | |
console.log(this.name + '在工作'); | |
} | |
//web 类 继承 person 类 原型链 + 对象冒充的组合继承模式 | |
function Web(){ | |
Person.call(this); // 对象冒充实现继承 | |
} | |
var w = new Web(); | |
w.run(); // 张三在运动 | |
w.work(); // 报错 对象冒充可以继承属性和方法,但是没办法继承原型链上的属性和方法 | |
// 原型链上的继承 ------------------------------ | |
function Person(){ | |
this.name = '张三'; | |
this.age = 20; | |
this.run = function(){ | |
console.log(this.name + '在运动'); | |
} | |
} | |
Person.prototype.sex = '男'; | |
Person.prototype.work = function(){ | |
console.log(this.name + '在工作'); | |
} | |
function Web(){ | |
} | |
// 继承了构造函数里的属性和方法以及原型链上的属性和方法 | |
web.prototype = new Person(); | |
// 原型链继承的问题 --------------------- | |
function Person(name,age){ | |
this.name = name; | |
this.age = age; | |
this.run = function(){ | |
console.log(this.name + '在运动'); | |
} | |
} | |
Person.prototype.sex = '男'; | |
Person.prototype.work = function(){ | |
console.log(this.name + '在工作'); | |
} | |
var p = new Person('李四',21); | |
p.run(); // 李四在运动 | |
function Web(name,age){ | |
} | |
web.prototype = new Person(); | |
var w = new Web('赵四',20); // 实例化子类的时候没法给父类传参 | |
w.run(); //undefined 在运动 | |
// 原型链 + 构造函数的组合继承模式 ------------------------ | |
function Person(name,age){ | |
this.name = name; | |
this.age = age; | |
this.run = function(){ | |
console.log(this.name + '在运动'); | |
} | |
} | |
Person.prototype.sex = '男'; | |
Person.prototype.work = function(){ | |
console.log(this.name + '在工作'); | |
} | |
function Web(name,age){ | |
Person.call(this,name,age); // 对象冒充 实例化子类可以给父类传参 | |
} | |
Web.prototype = new Person(); | |
var w = new Web('赵四',20); | |
w.run(); // 赵四在运动 | |
w.work(); // 赵四在工作 | |
// 原型链 + 对象冒充的另一种继承方式 --------------------- | |
function Person(name,age){ | |
this.name = name; | |
this.age = age; | |
this.run = function(){ | |
console.log(this.name + '在运动'); | |
} | |
} | |
Person.prototype.sex = '男'; | |
Person.prototype.work = function(){ | |
console.log(this.name + '在工作'); | |
} | |
function Web(name,age){ | |
Person.call(this,name,age); // 对象冒充 实例化子类可以给父类传参 | |
} | |
Web.prototype = Person.prototype; | |
var w = new Web('赵四',20); | |
w.run(); // 赵四在运动 | |
w.work(); // 赵四在工作 |
# 2、Typescript 中的类
# 2.1 定义类
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; | |
} | |
getName():string{ | |
return this.name; | |
} | |
setName(name:string):void{ | |
this.name = name; | |
} | |
run():void{ | |
console.log(this.name + '在运动'); | |
} | |
} | |
var p = new Person('张三'); | |
p.run(); // 张三在运动 | |
console.log(p.getName()); // 张三 | |
p.setName('李四'); | |
console.log(p.getName()); // 李四 |
# 2.2 继承
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 Web extends Person{ | |
constructor(name:string){ | |
super(name); | |
} | |
} | |
let w = new Web('李四'); | |
console.log(w.run()); // 李四在运动 |
子类在继承父类之后,还可以自己拓展新的方法
class Person { | |
name: string; | |
constructor(name: string) { | |
this.name = name; | |
} | |
run(): string { | |
return this.name + '在运动'; | |
} | |
} | |
var p = new Person('张三'); | |
console.log(p.run()); // 张三在运动 | |
class Web extends Person { | |
constructor(name: string) { | |
super(name); | |
} | |
work():string{ | |
return this.name + '在工作'; | |
} | |
} | |
let w = new Web('李四'); | |
console.log(w.run()); // 李四在运动 | |
console.log(w.work()); // 李四在工作 |
如果子类定义的方法在父类中已存在,执行子类方法
class Web extends Person { | |
constructor(name: string) { | |
super(name); | |
} | |
work():string{ | |
return this.name + '在工作'; | |
} | |
run(){ | |
return '子类' + this.name + '在运动'; | |
} | |
} | |
let w = new Web('李四'); | |
console.log(w.run()); // 子类李四在运动 | |
console.log(w.work()); // 李四在工作 |
# 2.3 类中的修饰符
typescript 里面定义属性的时候给我们提供了三种修饰符
# public
公有 在类里面 子类 类外面都可以访问
class Person { | |
public name: string; | |
constructor(name: string) { | |
this.name = name; | |
} | |
run(): string { | |
return this.name + '在运动'; | |
} | |
} | |
// 类外部访问共有属性 | |
let p = new Person('哈哈哈'); | |
console.log(p.name); // 哈哈哈 |
# protected
保护类型 在类里面和子类可以访问 类外面无法访问
class Person { | |
protected name: string; | |
constructor(name: string) { | |
this.name = name; | |
} | |
run(): string { | |
return this.name + '在运动'; | |
} | |
} | |
let p = new Person('张三'); | |
console.log(p.name); // 张三 但是语法不允许 |
# private
私有 在类里面可以访问,子类,类外部都没法访问
class Person { | |
private name: string; | |
constructor(name: string) { | |
this.name = name; | |
} | |
run(): string { | |
return this.name + '在运动'; | |
} | |
} | |
class Web extends Person{ | |
constructor(name:string){ | |
this.name = name; | |
} | |
work():string{ | |
return this.name + "在运动";// 这里就会报错 编译不通过 只能在 Person 里访问 | |
} | |
} |
# 2.4 静态属性和静态方法
直接用类名调用
静态方法里无法调用非静态属性
class Person{ | |
public name:string; | |
static age:number = 20; | |
constructor(name:string){ | |
this.name = name; | |
} | |
// 实例方法 实例化之后才能使用的方法 | |
run():void{ | |
console.log(this.name + '在运动'); | |
} | |
work():void{ | |
console.log(this.name + '在工作'); | |
} | |
static print(){ | |
console.log('静态方法' + this.age); | |
} | |
} | |
let p = new Person('张三'); | |
p.work(); // 张三在工作 | |
Person.print(); // 静态方法 20 | |
console.log(Person.age); //20 |
# 2.5 多态
父类定义一个方法不去实现 让继承他的子类去实现 每一个子类有不同的表现
多态属于继承
class Animal{ | |
name:string; | |
constructor(name:string){ | |
this.name = name; | |
} | |
eat():void{ // 具体吃什么不知道 继承他的子类去实现 每一个子类的体现不一样 | |
console.log('吃'); | |
} | |
} | |
class Dog extends Animal{ | |
constructor(name:string){ | |
super(name); | |
} | |
eat(): string { | |
return this.name + '吃骨头'; | |
} | |
} | |
class Cat extends Animal{ | |
constructor(name:string){ | |
super(name); | |
} | |
eat(): string { | |
return this.name + '吃猫粮'; | |
} | |
} | |
let dog = new Dog('小狗'); | |
let cat = new Cat('小猫'); | |
console.log(dog.eat()); // 小狗吃骨头 | |
console.log(cat.eat()); // 小猫吃猫粮 |
# 2.6 抽象类和抽象方法
typescript 中的抽象类 他是提供其他类的基类,不能直接被实例化。
用 abstract 关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
abstract 抽象方法只能放在抽象类中
抽象类和抽象方法用来定义标准
抽象方法不包含具体实现,并且必须在派生类中实现
Animal 要求她的子类必须包含 eat 方法
abstract class Animal{ | |
abstract eat():any; | |
name:string; | |
constructor(name:string){ | |
this.name = name; | |
} | |
} | |
class Dog extends Animal{ | |
// 抽象类的子类必须实现抽象类里面的方法 | |
constructor(name:string){ | |
super(name); | |
} | |
eat() { | |
console.log(this.name + '吃骨头'); | |
} | |
} | |
let dog = new Dog('小狗'); | |
dog.eat(); // 小狗吃骨头 | |
class Cat extends Animal{ | |
constructor(name:string){ | |
super(name); | |
} | |
catch():void{ | |
console.log(this.name + '抓老鼠'); | |
} | |
eat() { | |
console.log(this.name + '吃鱼'); | |
} | |
} | |
let cat = new Cat('小猫'); | |
cat.eat(); // 小猫吃鱼 |
# 五、接口
接口的作用,在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到了一种限制和规范的作用,接口定义了某一批类所需要遵守的规范,接口口不关心这些类内部的状态数据,也不关心这些类里方法的实现细节,他只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。typescript 中的接口类似于 java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。
# 1、属性接口
//ts 中定义方法 | |
function printLabel():void{ | |
console.log('printLabel'); | |
} | |
printLabel(); | |
// 参数进行约束 | |
function printLabel(label:string):void{ | |
console.log('pringLabel'); | |
} | |
printLabel('ts'); | |
//ts 这种自定义方法传入参数对 json 进行约束 | |
function printLabel(labelInfo:{'label':string}):void{ | |
console.log('printLabel'); | |
} | |
let labelJson = { | |
label:'ts' | |
} | |
printLabel(labelJson); |
接口:行为和动作的规范 对批量方法进行约束
// 就是传入对象的约束 属性接口 | |
interface FullName{ | |
firstName:string; | |
secondName:string; | |
} | |
function printName(name:FullName){ | |
// 必须传入对象 firstName secondName | |
console.log(name.firstName + '--' + name.secondName); | |
} | |
let obj = { | |
firstName:'liu', | |
secondName:'xin', | |
age:21 | |
} | |
printName(obj); | |
//------- 这种写法只能有符合要求的对象属性 | |
printName({firstName:'liu',secondName:'xin'}); |
// 对批量方法进行约束 | |
interface FullName{ | |
firstName:string; | |
secondName:string; | |
} | |
function printName(name:FullName){ | |
// 必须传入对象 firstName secondName | |
console.log(name.firstName + '--' + name.secondName); | |
} | |
function printInfo(info:FullName){ | |
console.log(info.firstName + info.secondName + info.age);// 这里的 age 不符合规范,编译会报错 | |
} | |
let obj = { | |
firstName:'liu', | |
secondName:'xin', | |
age:21 | |
} | |
let info = { | |
firstName:'liu', | |
secondName:'xin', | |
age:21 | |
} | |
printName(obj); | |
printInfo(info); |
# 2、接口可选属性
// 接口可选属性 | |
interface FullName{ | |
firstName:string; | |
secondName?:string; | |
} | |
function getName(name:FullName){ | |
console.log(name); | |
} | |
// 顺序没关系,类型和内容必须符合 | |
getName({firstName:'liu'}); | |
// 示例 ------------------------- | |
interface Config{ | |
type:string; | |
url:string; | |
data?:string; | |
dataType:string | |
} | |
function ajax(config:Config):void{ | |
let xht = new XMLHttpRequest(); | |
xht.open(config.type,config.url,true); | |
xht.send(config.data); | |
xht.onreadystatechange = function(){ | |
if(xht.readyState == 4 && xht.status == 200){ | |
if(config.dataType == 'json'){ | |
console.log(JSON.parse(xht.responseText)); | |
}else{ | |
console.log(xht.responseText); | |
} | |
} | |
} | |
} | |
ajax({ | |
type:'get', | |
url:'http://127.0.0.1:2001/restaurant/food/getClassList', | |
dataType:'json', | |
// data:'name=zhangsan' | |
}) |
# 3、函数类型接口
对方法传入的参数以及返回值进行约束
加密的函数类型接口
interface encrypt{ | |
(key:string,value:string):string; | |
} | |
let md5:encrypt = function(key:string,value:string):string{ | |
// 模拟操作 | |
return key+value; | |
} | |
console.log(md5('name','zhangsan')); //namezhangsan |
# 4、可索引接口
数组、对象的约束(不常用)
// 第一种 数组 | |
interface UserArr{ | |
[index:number]:string; | |
} | |
let arr:UserArr = ['1','2','3']; | |
console.log(arr[0]); | |
interface UserArr{ | |
[index:number]:any; | |
} | |
// 第二种 对象 | |
interface UserObj{ | |
[index:string]:string; | |
} | |
let obj:UserObj = {name:'20',age:'20'}; |
# 5、类类型接口
对类的约束和抽象类有点相似
interface Animal{ | |
name:string; | |
eat(str:string):void; | |
} | |
class Dog implements Animal{ | |
name:string; | |
constructor(name:string){ | |
this.name = name; | |
} | |
eat(str: string): void { | |
console.log(this.name + '吃' + str); | |
} | |
} | |
let dog = new Dog('小黑'); | |
dog.eat('骨头'); // 小黑吃骨头 | |
class Cat implements Animal{ | |
name: string; | |
constructor(name:string){ | |
this.name = name; | |
} | |
eat(str: string): void { | |
console.log(this.name + '吃' + str); | |
} | |
} | |
let cat = new Cat('小花猫'); | |
cat.eat('老鼠'); // 小花猫吃老鼠 |
# 6、接口扩展
接口可以继承接口
interface Animal{ | |
eat():void; | |
} | |
interface Person extends Animal{ | |
work():void; | |
} | |
class Programer{ | |
name:string; | |
constructor(name:string){ | |
this.name = name; | |
} | |
coding(code:string):void{ | |
console.log(this.name + code); | |
} | |
} | |
class Web extends Programer implements Person{ | |
// name:string; | |
constructor(name:string){ | |
super(name); | |
// this.name = name; | |
} | |
work(): void { | |
console.log(this.name + '在工作'); | |
} | |
eat(): void { | |
console.log(this.name + '喜欢吃饭'); | |
} | |
} | |
let w = new Web('小李'); | |
w.work(); // 小李在工作 | |
w.eat(); // 小李喜欢吃饭 | |
w.coding('敲代码'); // 小李敲代码 |
# 六、泛型
软件工程中。我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性,组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
# 1、常规
通俗理解 泛型就是解决接口、类、方法的复用性,以及对不特定数据类型的支持
泛型一般用 T
// 同时返回 string 类型和 number 类型 | |
// 泛型 可以支持不特定的数据类型 传入的参数和返回的参数一致 | |
function getData<A>(value:A):A{ | |
return value; | |
} | |
console.log(getData<string>('123')); // 参数必须是 string | |
console.log(getData<number>(123)); // 参数必须是 number | |
console.log(getData<boolean>(true)); |
# 2、泛型类
比如有个最小堆算法,需要同时支持返回数字和字符串两种类型。通过类的泛型来实现。
class MinClass<T>{ | |
public list: T[] = []; | |
add(value: T): void { | |
this.list.push(value); | |
} | |
min(): T { | |
let minNum = this.list[0]; | |
for (let i = 0; i < this.list.length; i++) { | |
if (minNum > this.list[i]) { | |
minNum = this.list[i]; | |
} | |
} | |
return minNum; | |
} | |
} | |
let m1 = new MinClass<number>(); // 实例化类 并且指定了类 T 代表的类型是 number | |
m1.add(1); | |
m1.add(3); | |
m1.add(2); | |
console.log(m1.min()); | |
let m2 = new MinClass<string>(); | |
m2.add('a'); | |
m2.add('v'); | |
m2.add('c'); | |
console.log(m2.min()); // 判断 ascall 码值 |
# 3、泛型接口
// 第一种 | |
interface ConfigFn{ | |
<T>(value:T):T; | |
} | |
let setData:ConfigFn = function<T>(value:T){ | |
return value; | |
} | |
console.log(setData<string>('张三')); | |
console.log(setData<number>(123)); | |
// 第二种 | |
interface ConfigFn<T>{ | |
(value:T):T; | |
} | |
function getData<T>(value:T):T{ | |
return value; | |
} | |
let myGetData:ConfigFn<string> = getData; | |
console.log(myGetData('20')); |
//// 使用泛型 | |
class MySqldb<T>{ | |
add(info:T):boolean{ | |
console.log(info); | |
return true; | |
} | |
update(info:T,id:number):boolean{ | |
console.log(info); | |
console.log(id); | |
return true; | |
} | |
} | |
//// 给 user 表增加数据 | |
//// 定义一个 user 类 | |
class User{ | |
userName:string | undefined; | |
password: string | undefined; | |
} | |
let user = new User(); | |
user.userName = '刘昕'; | |
user.password = 'liuxin'; | |
let db = new MySqldb<User>(); | |
db.add(user); | |
// 定义一个 articleCate 类 和数据库表进行映射 | |
class ArticleCate{ | |
title:string | undefined; | |
desc:string | undefined; | |
status:number | undefined; | |
constructor(params:{ | |
title:string | undefined, | |
desc:string | undefined, | |
status?:number | undefined | |
}){ | |
this.title = params.title; | |
this.status = params.status; | |
this.desc = params.desc; | |
}; | |
} | |
// 增加 | |
let a = new ArticleCate({ | |
title:'分类', | |
desc:'1111' | |
}); | |
let articleDb = new MySqldb<ArticleCate>(); | |
articleDb.add(a); | |
// 更新 | |
let updateA = new ArticleCate({ | |
title:'分类', | |
desc:'1111' | |
}); | |
articleDb.update(updateA,2); |
# 4、数据库接口示例
/* | |
功能 定义一个操作数据库的库 支持 mysql mssql mongoDB | |
要求 mtsql mssql mongoDb 功能一样 都有 add update delete get 方法 | |
注意 约束统一的规范 以及代码重用 | |
解决方案 需要约束规范所以要定义接口 需要代码重用所以需要使用泛型 | |
接口 在面向对象编程中 接口是一种规范的定义 它定义了行为和动作的规范 | |
泛型 通俗理解 泛型就是解决 类 接口 方法的复用性 | |
*/ | |
interface DBI<T>{ | |
add(info:T):boolean; | |
update(info:T,id:number):boolean; | |
delete(id:number):boolean; | |
get(id:number):any[]; | |
} | |
// 定义一个操作 mysql 数据库的类 | |
// 要实现泛型接口 这个类也应该是泛型类 | |
class MySqlDB<T> implements DBI<T>{ | |
constructor(){ | |
console.log('mysql数据库建立连接'); | |
} | |
add(info: T): boolean { | |
console.log(info); | |
return true; | |
} | |
update(info: T, id: number): boolean { | |
console.log(info); | |
console.log(id); | |
return true; | |
} | |
delete(id: number): boolean { | |
console.log(id); | |
return true; | |
} | |
get(id: number): any[] { | |
console.log(id); | |
return [{userName:'liuxin',password:'123456'}]; | |
} | |
} | |
// 定义一个操作 myssql 数据库的类 | |
class MssqlDB<T> implements DBI<T>{ | |
constructor(){ | |
console.log('mssql数据库建立连接'); | |
} | |
add(info: T): boolean { | |
console.log(info); | |
return true; | |
} | |
update(info: T, id: number): boolean { | |
console.log(info); | |
console.log(id); | |
return true; | |
} | |
delete(id: number): boolean { | |
console.log(id); | |
return true; | |
} | |
get(id: number): any[] { | |
console.log(id); | |
return [{userName:'liuxin',password:'123456'}]; | |
} | |
} | |
// 定义一个操作 mongoDB 数据库的类 | |
class MongoDB<T> implements DBI<T>{ | |
constructor(){ | |
console.log('mongo数据库建立连接'); | |
} | |
add(info: T): boolean { | |
console.log(info); | |
return true; | |
} | |
update(info: T, id: number): boolean { | |
console.log(info); | |
console.log(id); | |
return true; | |
} | |
delete(id: number): boolean { | |
console.log(id); | |
return true; | |
} | |
get(id: number): any[] { | |
console.log(id); | |
return [{userName:'liuxin',password:'123456'}]; | |
} | |
} | |
// 操作用户表 定义一个 User 类和数据表做映射 | |
class User{ | |
userName:string | undefined; | |
password:string | undefined; | |
} | |
let u = new User(); | |
u.userName = '张三'; | |
u.password = 'zhangsan'; | |
let mySql = new MySqlDB<User>(); | |
mySql.add(u); | |
let mssql = new MssqlDB<User>(); | |
// 添加数据 | |
mssql.add(u); | |
// 更新数据 | |
mssql.update(u,1); | |
// 获取数据 | |
console.log(mssql.get(1)); |
# 5、模块化
就是 es6 模块化的 ts 版
/* | |
模块的概念 | |
内部模块 称作为 命名空间 | |
外部模块 称作为 模块 | |
模块在其自身的作用域里执行 而不是全局作用域里 | |
export 导出需要被其他模块访问到的变量或者函数等 | |
import 导入需要引用的其他模块的变量或者函数等 | |
*/ |
# 6、命名空间
/* | |
命名空间 | |
在代码量较大的情况下,为了避免各种变量命名相冲突,可以将类似功能的函数、类、接口等放置到命名空间内 | |
同 java 的包、.net 的命名空间一样,typescript 的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。 | |
命名空间内的对象通过 export 导出 | |
命名空间与模块的区别 | |
命名空间 内部模块 主要用于组织代码,避免命名冲突 | |
模 块 ts 的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间 | |
*/ | |
namespace A{ | |
interface Animal{ | |
name:string; | |
eat():void; | |
} | |
export class Dog implements Animal{ | |
name:string; | |
constructor(name:string){ | |
this.name = name; | |
} | |
eat(): void { | |
console.log(this.name + '吃狗粮'); | |
} | |
} | |
export class Cat implements Animal{ | |
name: string; | |
constructor(name:string){ | |
this.name = name; | |
} | |
eat(): void { | |
console.log(this.name + '吃猫粮'); | |
} | |
} | |
} | |
namespace B{ | |
interface Animal{ | |
name:string; | |
eat():void; | |
} | |
export class Dog implements Animal{ | |
name:string; | |
constructor(name:string){ | |
this.name = name; | |
} | |
eat(): void { | |
console.log(this.name + '吃狗粮'); | |
} | |
} | |
export class Cat implements Animal{ | |
name: string; | |
constructor(name:string){ | |
this.name = name; | |
} | |
eat(): void { | |
console.log(this.name + '吃猫粮'); | |
} | |
} | |
} | |
let d = new A.Dog('狼狗'); | |
d.eat(); | |
let c = new B.Dog('小花'); | |
c.eat(); |
# 七、装饰器
- 是一种特殊类型的声明 它能够被附加到类声明,方法,属性或参数上,可以修改类的行为
- 通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能
- 常见装饰器有 类装饰器 属性装饰器 方法装饰器 参数装饰器
- 装饰器的写法 普通装饰器 (无法传参) 装饰器工厂 (可传参)
- 装饰器是过去几年中 js 最大的成就之一,已经是 es7 的标准特性之一
装饰器执行顺序
属性 > 方法 > 方法参数 (多个同类型装饰器顺序从后往前)> 类装饰器
// 装饰器 | |
function logClass(params:any):void{ | |
console.log(params); | |
//params 就是当前类 | |
params.prototype.apiUrl = '动态拓展的属性'; | |
params.prototype.run = function(){ | |
console.log('我是一个run方法'); | |
} | |
} | |
@logClass | |
class HttpClient{ | |
constructor(){ | |
} | |
getData(){ | |
} | |
} | |
let http = new HttpClient(); | |
console.log(http.apiUrl); // 动态拓展的方法 | |
http.run(); // 我是一个 run 方法 |
// 装饰器工厂 | |
function logClass(params:string){ | |
return function(target:any){ | |
console.log(params); //http://www.baidu.com/ | |
console.log(target); | |
target.prototype.apiUrl = params; | |
} | |
} | |
@logClass('http://www.baidu.com/') | |
class HttpClient{ | |
constructor(){ | |
} | |
getData(){ | |
} | |
} | |
let http = new HttpClient(); | |
console.log(http.apiUrl); //http://www.baidu.com/ |
# 1、类装饰器
function logClass(target:any){ | |
console.log(target); | |
return class extends target{ | |
apiUrl:any = '我是修改后的apiUrl'; | |
getData(){ | |
this.apiUrl = this.apiUrl + '----'; | |
console.log(this.apiUrl); | |
} | |
} | |
} | |
@logClass | |
class HttpClient{ | |
public apiUrl:string | undefined; | |
constructor(){ | |
this.apiUrl = '我是构造函数里的apiUrl'; | |
} | |
getData(){ | |
console.log(this.apiUrl); | |
} | |
} | |
let http = new HttpClient(); | |
http.getData(); // 我是修改后的 apiUrl---- |
# 2、属性装饰器
属性装饰器表达式会在运行时当作函数被调用,传入下列 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); // url | |
target[attr] = params; | |
} | |
} | |
@logClass('http://www.baidu.com/') | |
class HttpClient{ | |
@logProperty('http://www.liuxin.com/') | |
public url:any | undefined; | |
constructor(){ | |
} | |
getData(){ | |
console.log(this.url); | |
} | |
} | |
let http:any = new HttpClient(); | |
http.getData();//http://www.liuxin.com/ |
# 3、方法装饰器
它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义
方法装饰会在运行时传入下列 3 个参数
- 对于静态成员来说是类的构造函数,对于实力成员是类的原型对象
- 成员名字
- 成员的属性描述符
// 方法装饰器一 | |
function get(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('我是一个方法'); | |
} | |
} | |
} | |
class HttpClient{ | |
public url:any | undefined; | |
constructor(){ | |
} | |
@get('http://www.baidu.com/') | |
getData(){ | |
} | |
} | |
let http = new HttpClient(); | |
console.log(http.apiUrl); | |
http.run(); |
// 方法装饰器二 | |
function get(params:any){ | |
return function(target:any,methodName:any,desc:any){ | |
console.log(target); | |
console.log(methodName); | |
console.log(desc.value); | |
// 修改装饰器的方法 把装饰器方法里面传入的所用参数改为 string 类型 | |
// 保存当前的方法 | |
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('http://www.baidu.com/') | |
getData(...args:any[]){ | |
console.log(args); | |
console.log('我是getData里的方法'); | |
} | |
} | |
let http = new HttpClient(); | |
http.getData(123,'xxx'); //['123','xxx']; |
# 4、方法参数装饰器
参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列 3 个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 方法的名字
- 参数在函数参数列表中的索引
function logParams(params:any){ | |
return function(target:any,paramsName:any,paramsIndex:any){ | |
console.log(target); | |
console.log(paramsName); | |
console.log(paramsIndex); | |
target.apiUrl = params; | |
} | |
} | |
class HttpClient{ | |
public url:any | undefined; | |
constructor(){ | |
} | |
getData(@logParams('xxx') uuid:any){ | |
console.log(uuid); | |
} | |
} | |
let http:any = new HttpClient(); | |
http.getData(123456); | |
console.log(http.apiUrl); |