学习前端TS第二天

接口和应用场景

接口:interface 其实就是一种定义对象类型的类型

接口应用场景:

  • 一些第三方包或者框架底层中会有大量的接口类型
  • 提供方法的对象类型的参数使用
  • 为多个同类别的类提供统一的方法和属性声明

定义接口(其实感觉好像跟java中的class有那么一丢丢像)

interface Product{
 	name:string
 	price:number
 	account:number
 }
//声明
let p:Product={
	name:"phone",
	price:100,
	account:10
}//如果不根据接口中定义的属性和类型去声明就会报错	

继承接口

//继承
interface dog extends Pet{}//可以拓展父类的方法
class ArrayList implements List{}//会自动生成方法

可索引签名

interface Product{
	[x:string]:any
	price:number
}
//[x:类型]固定写法记住!

type A = Product["price"]
//可以直接拿到price的类型
//接口同名会合并

//这下面有两行代码先记住,等到泛型再理解
type AllKeys<T>=T extends any?T:never
type PKeys=AllKeys<keyof Product>

//any,unknown,undefined可以接受undefined
//any,unknown,null可以接受null

//rest参数
function info(name:string,age:number,...rest:any){}
//rest参数可以一直给

let data:unknown=undefined

interface和type区别

type和接口类似,都用于定义接口
但是区别:
1.定义类型不同
interface只能定义对象类型或者接口当名字的函数类型
type可以定义任何类型,包括基础类型、联合类型,交叉类型,元组
2.接口可以extends一个或者多个接口或类,也可以继承type,但是type类型没有继承功能,但一般接口继承 类和type的应用场景很少见
3.type交叉类型&可让类型中的成员合并成一个新的type类型,但接口不能交叉合并

type Group={groupName:string,memberNum:number}
type GroupInfoLog={info:string,happen:string}
type GroupMemeber=Group&GroupInfoLog//type交叉类型合并

let data:GroupMember={
groupName:"001",memberNum:10,
info:"集体爬山",happen:"中途有组员差点滑落,有惊无险',
}
export{}

4.接口可以合并声明
定义两个相同名称的接口会合并声明,但是type会报错

元组

  • 定义时每个元素的类型都确定
  • 元素值的数据类型必须事当前元素定义的类型
  • 元素值的个数必须和定义时个数相同

TS数组和数组元素怎么样同时为只读?

const account=[10,40,50,60,90] as const
account[1]=100;
//as const是关键,让别人改不了内部的数据

可变元组

let customers:[string,number,string,...any[]]=[]
//可变元组的关键就是那个any
//可变元组的解构
let [custname,age,address,...rest]:[custname_:string,age_:number,addr:string,...any[]] = [...]

定义:拥有相同属性和方法的一系列对象的集合

class People{
	name!:string;
	age!:number;
	addr!:string;
	static count:number=0;//静态对象是可以由所有的该类型通用且相同,且不由变量赋值改变。
	//constructor(_name:string,_age:number,_addr:string){
	//	this.name=_name;
	//	this.age=_age;
	//	this.addr=_addr;
	// People.count++
	doEat(){}
	doStep(){}
}//一定是要赋值的,如果你不想写构造函数就直接加!

TS单例模式的实现

//第一种实现方法,不好的地方就是只要跑起来,就创建好,有时候你不用它也会自动创建,浪费时间空间
class DateUtil{
	static dateUtil = new DateUtil()//立即创建单件模式
	private constructor(){}
	formarDate()
	diffDateByDay(){}
}
//静态对象的执行时机,会最先执行,且只会执行一次,并不会重复执行
//所以推荐第二种
class DateUtil{
	static dateUtil:DateUtil
	private constructor(){
		console.log("创建对象...")
	}
	static getInstance(){
		if(!this.dateUtil){
			this.dateUtil = new DateUtil()
		}
		return this.dateUtil
	}
}
//这种就可以自己控制,你想要创建对象,你就调用构造函数
const dateUtil1 = DateUtil.getInstance()
const dateUtil2 = DateUtil.getInstance()

getter和setter的存在意义

在加入一些属性的时候,可以添加一些限制
不要在构造函数里写这些方法,因为构造函数是对所有的属性,属性一多就会显得很乱。所以对于单个属性,设置get和set方法。

不同实例的方法声明会在不同的空间

class DateUtil{
	static dateUtil:DateUtil
	private constructor(){
		console.log("创建对象...")
	}
	static getInstance(){
		if(!this.dateUtil){
			this.dateUtil = new DateUtil()
		}
		return this.dateUtil
	}
	doEat(who:string,where:string){
		console.log(`who:${who},where:${where}`)
	}
}
const dataProp1 = Object.getOwnPropertyDescriptor(People.prototype,"doEat")
const dataProp2 = Object.getOwnPropertyDescriptor(People.prototype,"doEat")
console.log(dataProp1 === dataProp2)
//打印出false,说明开辟了新的空间

方法拦截器

用于方法调用前,或者之后的处理

class StringUtil{
	static trimSpace(str:string){
		return str.replace(/\s+/g,"")
	}
}
const dataProp1 = Object.getOwnPropertyDescriptor(People.prototype,"doEat")
const targetMethod = dataProp1!.value//这行代码可以取到他的方法
dataProp1!.value = function(...args:any[]){
	args = args.map((arg)=>{
		if(typeof arg === "string") return StringUtil.trimSpace(arg)
		return arg
	})
	console.log("前置拦截。。。")
	targetMethod.apply(this,args)
	console.log("后置拦截")
}
Object.defineProperty(People.prototype,"doEat",dataProp1!)
let p = new people("peter",23,"公主坟")
p.doEat("张 三","王 家 路")
export{}
//最终打印结果是张三,王家路
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值