1. class类
类的基础知识—ES6+ 类
1.1 constructor构造函数
类通过class关键字来定义一个类。
类可以有自己的构造函数constructor,当我们通过new关键字创建一个 实例时,构造函数会被调用。
构造函数不需要返回任何值,默认返回当前创建出来的实例。
class father {
// 在默认的strictPropertyInitialization模式下面我们的属性是必须初始
// 化的,如果没有初始化,那么编译时就会报错
name: string
money: number
//构造器
constructor(name: string, money: number = 200) {
this.name = name
this.money = money
}
getMoney() {
console.log("我家的钱", this.money)
}
}
const demo = new father("你好")
console.log(demo.money) //200
demo.getMoney()//我家的钱 200
1.2 类的继承
类通过关键字extends
关键字实现继承。子类中可以使用super
关键字来访问父类。
class father {
type: string
value: string
constructor(type: string, value: string) {
this.type = type;
this.value = value
}
show() {
console.log('我显示了');
return "显示"
}
}
class son extends father { //继承了father的实例成员
name: string
age: number
constructor(type: string, value: string, name: string, age: number) {
super(type, value) //调用父元素的type,value属性
this.name = name
this.age = age
}
text() {
console.log(this.type);
console.log(this.value);
console.log(this.name);
console.log(this.age);
super.show() //super调用父类方法
}
}
let demo = new son("文字", "值为0", "憨八龟", 19)
demo.text()
export { }
1.3 类的修饰符
在TypeScript中,类的属性和方法支持三种修饰符: public、private、protected。
- public: 默认值,公共属性,谁都可以访问。
- private:私有属性,只能在类内部进行访问 编程规范一般私有属性都是 _ 下划线开头
- protected:受保护的属性,只能在当前类和当前类的子类中使用和修改。
1.private
class User {
private name: string
constructor(name: string) {
this.name = name
}
}
let demo = new User("张三")
console.log(demo.name) //报错 name为私有属性
2. protected
class User {
protected name: string
constructor(name: string) {
this.name = name
}
}
class Student extends User {
constructor(name: string) {
super(name)
}
logUser() {
console.log(this.name)
}
}
let demo = new Student("张三")
demo.logUser() //张三
1.4 只读属性readonly
class User {
readonly name: string
constructor(name: string) {
this.name = name
}
}
let demo = new User("张三")
console.log(demo.name) //张三
demo.name = "李四" //报错 只读属性无法修改
1.5 setters/getters
前面一些私有属性我们是不能直接访问的,或者某些属性我们想要监听它的获取(getter)和设置(setter)的过程, 这个时候我们可以使用存取器。
class User {
private _name: string
constructor(name: string) {
this._name = name
}
set name(newName) {
this._name = newName
}
get name() {
return this._name
}
}
const demo = new User("张三")
console.log(demo.name); //张三
demo.name = "李四"
console.log(demo.name);
1.6 静态成员 static
使用static
开头的属性/方法成为静态属性(类属性),只能通过类去调用。
class User {
static admin: string = "张三"
static getAdmin() {
console.log("管理员是", this.admin)
}
}
//静态成员通过类名调用
console.log(User.admin) //张三
User.getAdmin()//管理员是张三
1.7 抽象类
抽象就是指不具体的,所以抽象类就是指不具体的类。所以抽象类自身没有什么功能,通常作为父类类使用。
抽象类是使用abstract声明的类。
抽象类是不能被实例的话(也就是不能通过new创建)。
抽象类规定了所有继承自它的非抽象子类必须实现它的所规定的功能和相关操作,否则会报错。
function CurrencyConverter(Fun: transfer) {
return Fun.converter()
}
// 抽象类规定了所有继承自它的**非抽象子类**必须实现它的所规定的功能和相关操作,否则会报错。
abstract class transfer {
abstract converter(): number
}
class usd extends transfer {
private money: number
constructor(money: number) {
super()
this.money = money
}
converter() {
return this.money * 6.3
}
}
const usdDemo = new usd(20)
console.log(CurrencyConverter(usdDemo)); //126
1.8 类的类型
类的本身也是可以作为一种数据类型。
class father {
name?: string = "张三"
constructor(name?: string) {
this.name = name
}
getMoney() {
console.log("我没钱")
}
}
function demo(f: father) {
console.log(f.name)
f.getMoney()
}
demo(new father("李四"))
demo({ name: "王五", getMoney: function () { console.log("我明明看见你有钱") } })
打印结果:
李四
我没钱
王五
我明明看见你有钱
2. 接口
接口的声明规范一般规定以I开头。
2.1 声明对象类型
接口的类型通过interface
关键字声明。注意接口中的所有属性都不能有实际的值,接口一般用于定义对象的结构。
interface IUser{
name:string
age?:number //可选
readonly money:number
readonly info:{
ss:number
}
fun:()=>void //接口中的所有方法都是抽象方法
}
let demo:IUser={
name:"张三",
money:200,
info:{
ss:200
},
fun(){
console.log("测试")
}
}
console.log(demo.name)//张三
console.log(demo.money)//200
console.log(demo.info.ss=300) //300
// console.log(demo.info={})//报错 因为是只读类型 可以修改值不能修改指向
在接口中我们可以定义对象中键值对的类型
2.2 函数类型
接口也可以用于定义函数类型,但是除了对象类型外,其他不推荐使用接口定义,最好使用type
。
interface count{
(nbr1:number,nbr2:number):number//定义函数类型
}
function getSum(n1:number,n2:number,countSum:count){
return countSum(n1,n2)
}
const add:count =(n1,n2)=>{
return n1+n2
}
console.log(getSum(20,30,add)) //50
2.3 接口的继承
接口与类有些不同,接口可以实现多继承。
interface inter1{
fun1:()=>number
}
interface inter2{
fun2:()=>void
}
interface collect extends inter1,inter2{ //多个继承用逗号隔开
}
const demo :collect={
fun1(){
return 20
},
fun2(){}
}
2.4 交叉类型
前面学习的联合类型|
等同于逻辑或,交叉类型&
等同于逻辑与。
interface color{
color:string
}
interface action{
change:()=>void
}
type colorType =color&action
const obj:colorType={
color:"red",
change(){
console.log("red")
}
}
obj.change()
2.5 接口的实现
接口的实现就是指类满足接口的所有需求。 通过implements
关键字实现接口。
interface IAdmin{
getPirce:()=>void
}
interface IUser{
getAge:()=>number
}
class role {
}
//类只能单继承 但是接口可以实现多个
class roleType extends role implements IAdmin,IUser{
getPirce(){
console.log(2000)
}
getAge(){
return 200
}
}
//案例2 公共API编写
function priceAction(price:IAdmin){
price.getPirce()
}
// 所有实现了接口的类所对应的对象, 都是可以传入
//1.直接传方法
priceAction({getPirce:function(){console.log("没钱了")}}) //没钱了
//2.传递实现了接口的类
priceAction(new roleType())//2000
2.6 接口与类型别名的不同
不同之处:
1.接口interface
允许命名重复,重复的对某个接口来定义属性和方法,ts内部会进行合并操作。
2.类型别名type
定义的是别名,别名是不能重复的
使用场景:
如果是定义非对象类型,通常推荐使用type,比如Direction、Alignment、一些Function。
2.7 字面量赋值
字面量赋值解决以下问题:(原则上字面量赋值仅仅是解决报错)
作用场景:后端有时候返回我们的数据有许多是我们封装的接口不需要的,如果直接赋值给接口会导致报错。这时候可以使用字面量赋值。
通过字面量赋值跳过错误:
interface IUser{
name:string
action:()=>void
}
const instance ={
name:"张三",
age:18,
action(){
console.log("运动")
}
}
/**
* 不报错原理:freshness擦除
* 1.首先将Instance的类型取出
* 2.擦除与IUser接口无关的声明 即age
* 3.检测instance对应的name和action类型是否相同
*/
const instance1:IUser = instance
console.log(instance1.name) //张三
console.log(instance1.age)//报错 类型“IUser”上不存在属性“age”。
函数使用:
interface IUser{
name:string
action:()=>void
}
function getUser(info:IUser){
console.log(info.action)
}
const instance ={
name:"张三",
age:18,
action(){
console.log("运动")
}
}
getUser(instance)
3. 枚举enum
枚举其实就是将一组可能出现的值,一个个列举出来,定义在一个类型中,这个类型就是枚举类型。
enum Money {
RMB = "RMB",
MY = "MY",
YB = "YB",
}
function moneyType(money: Money) {
switch (money) {
case Money.RMB:
console.log("人民币")
break
case Money.MY:
console.log("美元")
break
case Money.YB:
console.log("英镑")
break
default:
const foo: never = money
break
}
}
moneyType(Money.RMB) //人民币
3.1 枚举类型的值
枚举类型默认是有值的,值为索引:
例如:
enum Money {
RMB, //0
MY ,//1
YB ,//2
}
当我们赋值如果是数字后面的值会依次+1
enum Money {
RMB, //0
MY=2 ,//2
YB ,//3
}