TypeScript笔记
1.继承
Person{
name:string;
constructor(name:string){
this.name = name
}
run ():string{
return '${this.name}在运动'
}
}
class Daliy extends Person{
time:string;
constructor(name:string,time:string){
super(name)
this.time = time
}
info ():string{
return <code>${this.time}${this.name }还在工作</code>// <code></code>,模板字符串" ` "是tab键上面那个按钮,不是单引号!!!
}
static print(){
alert('这是静态方法')
}
}
var w = new Daliy('浩浩',new Date().toLocaleTimeString())
alert(w.info())
2.多态
父类定义一个方法不去实现,让继承他的子类去实现,且子类有不同的表现
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}吃肉`
}
}
var c = new Cat('猫')
alert(c.eat())
3.抽象类
(1)它是提供其他类继承的基类,不能直接被实例化
(2)用abstract关键字定义抽象类和抽象方法
(3)抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。
(4)abstract抽象方法只能放在抽象类里面
//抽象类和抽象方法用来定义标准,标准:Animal 这个类要求它的子类必须包含eat方法
abstract class Pet{
name:string
constructor(name:string){
this.name = name
}
abstract eat():any;//不包含具体实现,abstract eat():any代表有返回值,abstract eat():void代表没有返回值
}
// var pet = new Pet('狗') 错误写法,抽象类不能直接实例
class Dog extends Pet{
constructor(name:string){
super(name)
}
eat(){
return `${this.name}吃肉`
}
}
var dog = new Dog('狗')
console.log('抽象类:'+dog.eat())
4.接口
(1)接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。
(2)接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。
(3)typescrip中的接口类似于java, 同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。
4.1属性接口(对传入对象的约束)
interface AllName{
firstName:string;
lastName:string
}
function pName(name:AllName){
//必须传入对象{ firstName,lastName}
console.log('接口:' + name.firstName +'-------------'+ name.lastName)
}
let obj = { //必须包含接口中定义的属性
age:20,
firstName:'张',
lastName:'三'
}
pName(obj)
4.2ts封装一个ajax请求
interface ajaxConfig{
dataType:string;
data?:string;//代表data是可选的
type:string;
url:string
}
function ajax(config:ajaxConfig){
var xhr =new XMLHttpRequest();
xhr.open(config.type,config.url,true)//true代表异步,表示在send()之后执行,而不用等待服务器响应
xhr.withCredentials = true;
xhr.send(config.data)
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
if(config.dataType === 'jsonp'){
console.log('ts封装ajax: ' + JSON.parse(xhr.responseText))
console.log(JSON.parse(xhr.responseText))
// let aaa =document.getElementById('text')?.innerHTML
// if(aaa){
// aaa= JSON.parse(xhr.responseText).showapi_res_body.data
// }
}else{
console.log(xhr.responseText)
}
}
}
}
let obj2 ={
url:'接口的url
,type:'get'
,dataType:'jsonp'
,data:'success'
}
ajax(obj2)
4.3.函数类型接口(对方法传入的参数以及返回值进行约束)
interface encrypt{
(key:string,value:string):string
}
var md5:encrypt = function(key:string,value:string):string{
key = 'key是:' + key,
value = 'vlue是:' + value
return `${key},${value}`
}
console.log('函数类型接口:' + md5('键','值'))
4.4类类型接口,通过implements关键字来实现父接口
interface Animal2{
name: string;
eat(str: string): void;
}
class Dogs implements Animal2{
name: string; // 属性
constructor(name: string){ // 构造函数 接收实例化的参数
this.name = name;
}
eat(){
console.log('类类型接口:' + this.name + '吃骨头')
}
}
var d= new Dogs('小狗子');
d.eat();
4.5接口扩展:接口可以继承接口
// WorkerPerson 接口
interface WorkerPerson{
name: string;
eat(str: string): void;
}
// ProWorker 接口 继承 WorkerPerson 接口
interface ProWorker extends WorkerPerson{
work(): void;
}
// 实现ProWorker接口
class Man implements ProWorker{
public name: string;
constructor(name:string){
this.name = name
}
eat(){
console.log('接口的扩展:' + this.name + '吃米饭')
}
work(params: string='改bug'){
console.log('接口的扩展:' + this.name + params)
}
}
var m = new Man('程序员');
m.eat();
m.work();
5.泛型:解决类、接口、方法的复用性,以及对不特定数据类型的支持
泛型可以支持不特定的类型,要求:传入参数和返回参数一致
T代表泛型,具体是什么类型由调用这个方法时决定
5.1泛型函数
function getData<T>(value:T):T{
return value;
}
console.log('泛型函数:' + getData('字符串类型'))
console.log('泛型函数:' + getData(12356))//数值类型
5.2泛型类
例:有一最小堆算法,需支持同时返回字符串和数字两种类型,通过类的泛型来实现
class Minclass<T>{
public list:T[] = []
add(value:T){
this.list.push(value)
}
min():T{
let dataMin = this.list[0]
for(let i=1;i<this.list.length;i++){
if(dataMin > this.list[i]){
dataMin = this.list[i]
}
}
return dataMin
}
}
let minn = new Minclass<number>()//实例化类,并指定T的类型为number
minn.add(5)
minn.add(3)
minn.add(1)
console.log('泛型类:最小值为----' + minn.min() + '(number类型)')//1
let minn2 = new Minclass<string>()//实例化类,并指定T的类型为string,字符串按ASCII编码排序
minn2.add('a')
minn2.add('r')
minn2.add('g')
console.log('泛型类:最小值为----' + minn2.min() + '(string类型)')//a
例:定义一个User类,这个类的作用就是映射数据库字段;定义一个MySqlDB类用于操作数据库,然后把User类当作参数传入到MySqlDB中(把类当作参数来约束数据传入的类型)
-----------------一般写法-----------------
class MySqlDB{
add(user:User):boolean{//引入User类作为参数,返回值为true或false(即boolean)
console.log('类为参数:User如下')
console.log(user)
return true
}
}
//User类
class User{
name:String | undefined //省略了public
password:String | undefined//省略了public
}
let u = new User()
u.name='root',
u.password='123456'
let NewMysql = new MySqlDB()
NewMysql.add(u)
//ArticleCate类
class ArticleCate{
title:string | undefined
price:number | undefined
sale?:boolean | undefined//可选参数
constructor(params:{title:string | undefined,price:number | undefined,sale?:boolean | undefined})
{
this.title = params.title
this.price = params.price
this.sale = params.sale
}
}
let objA = {
title:'java基础',
price:35.00,
sale:true
}
let Art = new ArticleCate(objA)
let NewMyArt = new MySqlDB<ArticleCate>()
NewMyArt.add(Art)
-----------------泛型类写法-----------------
class MySqlDB<T>{
add(user:T):boolean{//引入User类作为参数,返回值为true或false(即boolean)
console.log('泛型类--类为参数:User如下:')
console.log(user)
return true
}
}
class User{
name:String | undefined //省略了public
password:String | undefined//省略了public
status:number | undefined
}
// add()添加方法
let u = new User()
u.name='root',
u.password='123456'
u.status = 1
let NewMysql = new MySqlDB<User>()
NewMysql.add(u)
// update()修改方法
let objA = {
title:'java基础',
price:35.00,
sale:true
}
let Art = new ArticleCate(objA)
let NewMyArt = new MySqlDB<ArticleCate>()
NewMyArt.update(Art,2)
5.3泛型接口
5.3.1写法1
interface Demo {
<T>(value:T):T
}
var getDemo:Demo = function<T>(value:T):T{
return value
}
console.log('泛型接口1:'+getDemo<number>(12)+'-----'+typeof(getDemo(12)))//泛型接口1:12-----number
console.log('泛型接口1:'+ getDemo<string>('a')+'-----'+typeof(getDemo('a')))//泛型接口1:a-----string
5.3.2写法2
interface Demo2<T>{
(value:T):T
}
function getDemo2<T>(value:T):T{
return value
}
let myGetDemo2:Demo2<number> = getDemo2
console.log('泛型接口2:'+myGetDemo2(123)+'-----'+typeof(myGetDemo2(123)))//泛型接口2:123-----number
let myGetDemo:Demo2<string> = getDemo2
console.log('泛型接口2:'+myGetDemo('abc')+'-----'+typeof(myGetDemo('abc')))//泛型接口2:abc-----string
6.TypeScript类型、接口、类、泛型的综合使用
功能:定义一个操作数据库的库 支持 Mysql Mssql MongoDb
要求1:Mysql MsSql MongoDb功能一样 都有 add update delete get方法
注意:约束统一的规范、以及代码重用
解决方案:需要约束规范所以要定义接口 ,需要代码重用所以用到泛型
1、接口:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范
2、泛型 通俗理解:泛型就是解决 类 接口 方法的复用性、
//步骤1:定义一个数据库接口 DBI
interface DBI<T>{
add(info:T):boolean
update(info:T,id:number):boolean
delete(id:number):boolean
get(id:number):any[]
}
// 步骤2:定义操作相应数据库的类
//--------------------要实现一个泛型接口这个类也要是泛型类--------------------
//定义一个操作Mysql数据库的类
class MysqlDB<T> implements DBI<T>{
constructor(){
console.log('Mysql数据库建立连接')
}
add(info: T): boolean {
console.log('操作Mysql数据库add方法:',info)
return true
}
update(info: T, id: number): boolean {
return true
}
delete(id: number): boolean {
return true
}
get(id: number): any[] {
let list = [
{
userName:'浩浩',
PassWord:'haohao'
},
{
userName:'苏苏',
PassWord:'susu'
},
]
return list
}
}
// 定义一个操作MsSql数据库的类
class MsSqlDB<T> implements DBI<T>{
constructor(){
console.log('MsSql数据库建立连接')
}
add(info: T): boolean {
return true
}
update(info: T, id: number): boolean {
console.log('操作msSql数据库update方法:',info,'id为:',id)
return true
}
delete(id: number): boolean {
return true
}
get(id: number): any[] {
let list = [
{
userName:'浩浩',
PassWord:'haohao'
},
{
userName:'苏苏',
PassWord:'susu'
},
]
return list
}
}
//定义一个操作MongoDb数据库的类
class MongoDB<T> implements DBI<T>{
constructor(){
console.log('MongoDB数据库建立连接')
}
add(info: T): boolean {
return true
}
update(info: T, id: number): boolean {
return true
}
delete(id: number): boolean {
return true
}
get(id: number): any[] {
let list = [
{
userName:'浩浩',
PassWord:'haohao'
},
{
userName:'苏苏',
PassWord:'susu'
},
]
return list
}
}
// 步骤3:操作用户表 定义一个Admin类和数据表做映射
// 调用MysqlDb类
class admin{
UserName:string | undefined
PassWord:String | undefined
}
let adm = new admin()
adm.UserName = '浩浩'
adm.PassWord = 'root'
let OmySql = new MysqlDB<admin>()//类作为参数来约束传入数据的类型
OmySql.add(adm)
console.log('操作Mysql数据库get方法:',OmySql.get(2))
//调用MsSqlDBl类
class NewAdmin{
UserName:string | undefined
PassWord:String | undefined
}
let Nadm = new NewAdmin()
Nadm.UserName = '浩浩'
Nadm.PassWord = 'root'
let OmsSql = new MsSqlDB<NewAdmin>()//类作为参数来约束传入数据的类型
OmsSql.update(Nadm,2)
console.log('操作msSql数据库get方法:',OmsSql.get(2))
7.命名空间和模块的区别
在代码量较大的情况下,为了避免各种变量命名相冲突,可将相似功能的函数、类、接口等放置到命名空间内。
同Java的包、.Net的命名空间一样,TypeScript的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。命名空间内的对象通过export关键字对外暴露。
7.1命名空间和模块的区别:
7.1.1命名空间:内部模块,主要用于组织代码,避免命名冲突。
7.1.2模块:ts的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间。
7.2模块及模块化封装
我们可以把一些公共的功能抽离为一个单独文件作为一个模块,模块里的内容是私有的,若我们想在模块外使用则应先用export关键字将模块里的内容暴露,再在想使用的文件里用import关键字引入。(当前浏览器暂不支持export和require,可以讲代码用webpack打包。webpack打包教程链接:https://blog.youkuaiyun.com/qq_35617751/article/details/106635859)
let dburl='xxxxxxxxxxx'
//导出方法1
export function getDB():any[]{
console.log('获取数据库的数据')
let list = [
{
userName:'浩浩',
PassWord:'haohao'
},
{
userName:'苏苏',
PassWord:'susu'
},
]
return list
}
export function add():any{
return `数据添加成功!!`
}
//导出方法2
// export {getDB,add}
//导出方法3
// export default getDB --------------export default xxxx 只能使用一次----------
//引入方法1
import {getDB,add} from './modules/dbmodules';//表示调用模块里的方法
console.log('我是模块里的getDB方法:',getDB())
console.log('我是模块里的add方法:',add())
//引入方法2
// import {getDB as get,add} from './modules/dbmodules';//表示调用模块里的方法-------给getDB重命名
// console.log('我是模块里的getDB方法:',getDB())
// console.log('我是模块里的add方法:',add())
// 引入方法3
// import getDB from './modules/dbmodules';
// console.log('我是模块里的getDB方法:',getDB())
7.3命名空间
export namespace A{
interface Animal{
name: string;
eat(str: string): void;
}
export class Dogs implements Animal{
name: string; // 属性
constructor(name: string){ // 构造函数 接收实例化的参数
this.name = name;
}
eat(){
console.log('28、命名空间--类类型接口:' + this.name + '吃骨头')
}
}
}
export namespace B{
interface Animal{
name: string;
eat(str: string): void;
}
export class Dogs implements Animal{
name: string; // 属性
constructor(name: string){ // 构造函数 接收实例化的参数
this.name = name;
}
eat(){
console.log('29、命名空间--类类型接口:' + this.name + '吃肉')
}
}
}
//命名空间
import {A,B} from './modules/dbmodules'
var d1= new A.Dogs('小狗子');
d1.eat();
var d2= new B.Dogs('星星');
d2.eat();
8.装饰器
装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。
通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
装饰器的写法:普通装饰器(无法传参) 、 装饰器工厂(可传参)
8.1类装饰器:类装饰器在类声明之前被声明(紧靠着类声明)。
类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。 传入一个参数
8.1.1 类装饰器:普通装饰器(无法传参)
function logClass(params:any){
//params就是当前类
params.prototype.ApiUrl = 'xxxxxxx'
params.prototype.run = function(){
console.log('31、普通装饰器:我是run方法')
}
}
@logClass
class HttpClient{
constructor(){
}
getCoontent (){
}
}
let httpp:any = new HttpClient()
console.log('30、普通装饰器(动态扩展的属性)',httpp.ApiUrl)
httpp.run()
8.1.2 类装饰器:类装饰器工厂(可传参)
function decoClass(params:any){
return function(target:any){
console.log('32、类装饰器工厂:我是target-----',target)
console.log('33、类装饰器工厂:我是params-----',params)
target.prototype.ApiUrl = params
}
}
@decoClass('file:///G:/TypeScript/index.html')//给params赋值
//newHttp类为target内容
class newHttp{
constructor(){
}
getCoontent (){
}
}
let newhtpp:any = new newHttp()
console.log('34、类装饰器工厂:我是target的ApiUrl-----',newhtpp.ApiUrl)
8.1.3重载构造函数
类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一参数
若类装饰器返回一个值,它会使用提供的构造函数来替换类的声明
function oneLogClass(target:any){
return class extends target{
oneUrl:any = '我是修改后的url'
getData(){
this.oneUrl = '-----------' + this.oneUrl
console.log('36、类装饰器:重载构造函数',this.oneUrl)
}
}
}
@oneLogClass
class oneClass{
public oneUrl:string | undefined;
constructor(){
this.oneUrl = '我是默认的url'
}
getData(){
console.log('35、类装饰器:重载构造函数',this.oneUrl)
}
}
let a =new oneClass()
a.getData()
8.2属性装饰器:属性装饰器表达式在运行时被当作函数来调用
传入以下两个参数
(1)对于静态成员来说事类的构造函数,对于实例成员是类的原型对象
(2)成员的名字
//类装饰器
function logClass1(params:any){
return function(target:any){
console.log('37、属性装饰器---类装饰器:我是target-----',target)
console.log('38、属性装饰器---类装饰器:我是params-----',params)
target.prototype.ApiUrl = params
}
}
//属性装饰器
function logProterty(params:any){
return function(target:any,atrrName:any){
target[atrrName] = params
}
}
@logClass1('https://www.baidu.com/')//给params赋值
//newHttp类为target内容
class httpClient{
@logProterty('我是属性装饰器')
public httpUrl:string | undefined //属性
constructor(){
}
getCoontent (){
console.log('40、属性装饰器:我是httpClient的httpUrl-----',this.httpUrl)
}
}
let newHttpClient:any = new httpClient()
console.log('39、属性装饰器:我是target的ApiUrl-----',newHttpClient.ApiUrl)
newHttpClient.getCoontent()
8.3方法装饰器:被应用到方法的属性描述附上,可用来监视、修改或替换方法定义
在运行时传入3个参数:
(1)对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象
(2)成员的名字
(3)成员的属性描述符
//方法装饰器
function methodLog(params:any){
return function(target:any,methodName:string,describe:any){
console.log('41、方法装饰器:原型对象----',target,',----当前方法名----',methodName,',----当前方法内容----',describe.value)
target.httpUrl = params
//修改装饰器的方法 把装饰器方法里面传入的参数都改为string类型
/*
步骤(1)保存当前方法
*/
let nowMethod = describe.value
describe.value = function(...args:any[]){//...args表示所有传入的参数
args = args.map((value)=>{//在args.map的回调函数里把每一个参数都变为String类型
return String(value)
})
console.log('42、方法装饰器----方法装饰器输出----处理过的getCoontent方法的参数:',args)
//以上代码可做替换方法使用
//以下代码为修改方法(方法冒充)
nowMethod.apply(this,args)//this指当前方法,args指处理过后的参数
}
}
}
class httpClientMethod{
public httpUrl:string | undefined //属性
constructor(){
}
@methodLog('ssss')
getCoontent(...args:any[]){
console.log('43、方法装饰器----getCoontent方法输出----getCoontent方法的处理过的参数:',args)
console.log('44、方法装饰器----getCoontent方法输出----httpClientMethod的httpUrl:',this.httpUrl)
}
}
let hClientM:any = new httpClientMethod()
hClientM.getCoontent(11111,'dsfsgd',123)
8.4方法参数装饰器:参数装饰器表达式在运行时当作函数来调用,可使用参数装饰器为类的原型增加一些元素数据(使用较少)
传入以下3个参数
(1)对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象
(2)方法名称
(3)参数在函数参数列表里的索引
//方法参数装饰器
function logParams(params:any){
return function(target:any,MethodsName:any,paramsIndex:any){
console.log('45、方法参数装饰器:原型对象----',target,',----当前方法名----',MethodsName,',----参数索引----',paramsIndex)
target.methodsParams = params //为类的原型增加元素数据
}
}
class httpClientMethod2{
public httpUrl:string | undefined //属性
constructor(){
}
getCoontent(@logParams('id') id:any){
console.log('46、我是方法参数装饰器的getCoontent方法')
}
}
let MethodParams:any = new httpClientMethod2()
MethodParams.getCoontent('12321')
console.log('47、我是方法参数装饰器的参数methodsParams:',MethodParams.methodsParams)