深入理解类和接口

面向对象概述

  • TS 为前端面向对象带来了好处,JS 没有类型检查,如果使用面向对象的方式开发,会产生大量的接口,而大量的接口会导致调用复杂度剧增,这种复杂度必须通过严格的类型检查来避免错误。
  • 面向对象中有许多非常成熟的模式,能处理复杂问题

类的继承

  • 可以覆盖父类中的同名属性、方法,但是不能覆盖类型,类型需要跟父类保持一致
  • 类型匹配:子类的对象始终可以赋值给父类,但是赋值后只能使用父类的成员
class Person {
	name: ''
}
class Child {
	age: 20
}
let ch:Person = new Child() // ch.age 不能使用,只能使用 ch.name,需要使用类型保护,如下:
if(ch instanceOf Child) {
	console.log(ch.age  )
}
  • 修饰符号:protected 只能在自身和子类内部访问
  • supter 关键字:在子类的方法中,可以使用 super.xxx 关键字读取父类成员
  • 单根性和传递性:单根性是指:每个类最多只能拥有一个父类,传递性是指:如果 A 是 B 的父类, 并且 B 是 C 的父类,那么可以认为 A 是 C 的父类。

抽象类

有时,某个类只表示一个抽象概念,主要用于提取子类共有的成员,而不能直接创建它的对象,该类可以作为抽象类,其他类可以继承它

abstract class Person {}

如何抽象成员:父类中可能知道有些成员是必须存在的,但是不知道该成员的直或实现是什么,因此,需要有一种强约束,让继承该类的必须要实现该成员。 直接给成员加上 abstract。

abstract class Person {
    abstract name:string
    abstract age:number
    abstract height:number
    
}

class child extends Person {
    constructor(public name:string, public age:number, public height:number){
        super()
    }
}

抽象类也可以继承抽象类,而且可以不用实现父类的方法,让继承它的非抽象子类去实现

静态成员

静态成语是指,附着在类上的成员,可以直接通过类.xxx 来访问的成员,不用通过创建实例,并且在实例中也访问不到。

class Person {
	static walk(step):void {
		console.log('walk' + ' ' + step )
	}
}
Person.walk(10)

静态函数的 this 指向当前类不是实例

单例模式

class Person {
	private constructor(){} // 将构造函数私有化,那么就不能再外部调用 new 来实例化
	static readonly _Person:Person = new Person()
	// 上面的代码就算在不需要的时候也会在初始化的时候创建,可以像下面这样
	static _Person:Person
	init():Person{
		if(Person._Person) {
			return Person._Person
		}
		Person._Person = new Person()
		return Person._Person
	}
}

再谈接口

面向对象领域中的接口的用处是用来表达某个类是否拥有某种能力

interface Language {
   speakEnglish():void,
   speakChinese():void
}

class Person {
   constructor(
       public name:string,
       public age:number
   ) {}
}

class Child extends Person implements Language {
   speakEnglish(): void {
   }
   speakChinese(): void {
   }
}

接口也可以继承类,接口可以多继承

class A extends B, C {}

索引器

class A { name: 'xxx' }
const a = new A()
console.log(a.name) //1
console.log(a['test'])//2

对于第二种写法 Ts 不会做类型检查,如果想要开启这种检查,需要设置 "noImpliciAny": true,开启对隐式 any 类型的检查。默认情况下如果不开启,那么第二种判断不出到底是什么什么类型时(这里是一个常量,有可能是一个变量或者函数等不可预知的),那么会使用 any 类型,这个时候就会通过 TS 的类型检查。开启之后就会对这些情况进行报错。但是这个配置也不仅会影响到索引器,其他地方也会受到更严格的检查,例如声明函数时,参数未指明类型也会报错。

如果想开启动态添加属性,即添加一个类中没有的属性,可以像下面这样写

class A {
	[prop:string]:any // 用来约束所有的属性, [] 里面的表示键的类型,: 后面的表示属性值的类型,这个就叫索引器,需要放到类的顶部
}
const a = new A()
a.b = 1
a['c'] = 2

this 指向约束

ES6 中的类的内部使用的是严格模式,因此内存的函数如果没有通过 实例.xxx 去调用,那么默认是 undefined。在 TS 中默认对于用字面量声明的对象里函数的 this,TS 认为是 any 类型,而 class 内部的 this 类型认为是当前类.
Ts 中提供了一种选项,配置 noImplicitThis 为 true 后,表示不允许 this 隐式的指向 any,即需要声明 this 的指向,因此如果在书写函数时,在内部使用了 this,需要声明该函数 this 的指向,将 this 作为函数的第一个参数,如下

interface Func {
    name: string,
    age: number,
    say(this:Func):void,
    talk(this:Func): void,
}
let func:Func = {
    name: 'fjdslk',
    age: 13,
    say() { // 不要写箭头函数,因为箭头函数的 this 是跟当前上下文有关,无法约束
        console.log(this.name)
    },
    talk() {
        console.log(this.name)
    }
}

let say = func.say // this 丢失
say()// 开启后这里会报错,因为 this 指向错误
class A {
    name:string = 'fjldsfd'
    say(this:A) {
        console.log(this.name)
    }
}

let a = new A()
const say = a.say
say() // 同样的这里也会报错,因为 this 指向错误
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值