在js中,类(Class)定义了一件事物的抽象特点,包含它的属性和方法。对象(Object)为类的实例,可以通过new关键字生成。
面向对象的三大特性:封装,继承,多态
封装:将对数据的操作细节隐藏起来,只暴露对外的接口。通过对外提供的接口来访问该对象,同时也保证外界无法任意更改对象内部的数据。
继承:子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
多态:由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。
存取器(getter&setter):用以改变属性的读取和赋值行为。
修饰符:一些用于限定成员或类型的性质的关键字。例如public
- TypeScript中类的用法:
class Person{
name: string
age:number
gender:string
constructor(name:string='Liane',age:number=18,gender:string='female'){
this.name = name
this.age = age
this.gender = gender
}
sayHi(str:string){
console.log(`Hi ${str}, My name is ${this.name}, I'm ${this.age} years old`)
}
}
let p0 = new Person()
p0.sayHi('Ann')
继承:
使用extends关键字,让子类继承自父类,使用super关键字调用父类的构造函数和实例方法,继承父类的属性和方法
class Students extends Person{
constructor(name: string, age:number,gender:string){
super(name,age,gender)
}
sayHi(str){
super.sayHi(str)
}
}
let s0 = new Students('Jack',16,'man');
s0.sayHi('Liane')
- 多态:
由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。
class Animal{
name: string
constructor(name: string){
this.name = name
}
eat(str:string){
console.log(`${this.name} like to eat ${str}`)
}
}
class Dog extends Animal{
constructor(name:string='Tom'){
super(name)
}
eat(str){
super.eat(str)
}
}
class Cat extends Animal{
constructor(name:string='Jerry'){
super(name)
}
eat(str:string){
super.eat(str)
}
}
let dog = new Dog()
let cat = new Cat()
dog.eat('bone') //Tom like to eat bone
cat.eat('fish') //Jerry like to eat fish
即Dog和Cat都继承自Animal,但分别实现了自己的eat方法。
- 类中的成员修饰符
用来描述类中的属性、构造函数和方法的可访问性
public:默认修饰符,代表是公共的,在任何位置都可以被访问。
private:私有修饰符,外部和子类都无法访问这个成员。
当希望有的成员无法直接存取时,可使用private修饰符修饰该成员。
使用private修饰constructor时,该类不允许被继承或者实例化。
protected:该修饰符修饰的成员,只能在其内部及子类中被访问
使用protected修饰constructor时,该类只允许被继承,不允许实例化。
注:仅在TS编译时提示错误,在编译成js后,并没有限制private属性在外部的可访问性或protected修饰构造函数的可实例化性。
- readonly修饰符
修饰类中的属性成员,被修饰的属性不能在外部或类中的普通方法中被随意修改。可以在构造函数constructor中被修改。
//readonly修饰类中的属性
class Person{
readonly name:string='jack' //可设置默认值
constructor(name:string){
this.name = name //可以在构造函数中修改name
}
sayHi(){
this.name = 'Hello' //提示错误
}
}
let p = new Person('Liane')//允许实例化传入新的name值
p.name = 'Ann' //提示错误
console.log(p.name) //Ann--即使提示错误,但若继续编译,编译后的js依然不会限制修改readonly修饰的属性
使用readonly修饰constructor的参数时,被修饰的参数称为参数属性
class Person{
constructor(readonly name:string){
this.name = name
}
}
let p1 = new Person('Liane')
consoel.log(p1.name) //Liane
p1.name = 'Jack' //提示错误
//我们发现,在cosntructor的参数前加上修饰符readonly,则该类中会自动添加一个被readonly修饰的属性成员,类比不难发现,构造函数参数使用public,private,protected与使用readonly一致。
构造函数中的参数可以使用readonly进行修饰,一旦修饰,则该类中就有了这个只读参数的成员属性,外部可以访问,但不能修改。
同理,构造函数中的参数可以使用public,private和protected进行修饰,无论是哪个修饰符,该类中都会自动添加一个被该修饰符修饰的属性成员。
- 存取器
让我们可以有效的控制对对象中的成员的访问和修改。通过getter和setter来进行操作。
class Person{
firstName: string
lastName: string
constructor(firstName:string,lastName:string){
this.firstName = firstName
this.lastName = lastName
}
get fullName(){
return this.firstName + '_' +this.lastName
}
set fullName(value){
const names = value.split('_')
this.firstName = names[0]
this.lastName = names[1]
}
}
let p = new Person('诸葛','孔明')
console.log(p.fullName) //诸葛_孔明
p.fullName = '司马_相如'
console.log(p.firstName) //司马
- 静态成员
在类中通过static修饰的属性或方法,称为静态属性和静态方法,也称为静态成员。静态成员不会被实例继承,但可以被子类继承。
静态成员使用时通过类名.xxx的语法来调用
class A{
static n:number = 0
static fun(){
A.n++
console.log(A.n)
}
}
let a0 = new A()
console.log(a0.n) //提示错误,继续编译后会打印undefined
console.log(a0.fun()) //提示错误,编译后会报错
console.log(A.n) //0
A.n = 100
console.log(A.n) //100
A.fun() //101
- 抽象类
抽象类:包含抽象方法(抽象方法一般没有任何具体内容的实现),也可以包含实例方法,抽象类是不能被实例化的,为了让子类进行实例化及实现内部的抽象方法。
使用abstract定义一个抽象类和其中的抽象方法。
//定义一个抽象类
abstract class Animal1{
name:string
age: number
constructor(name:string,age:number){
this.name = name
this.age = age
}
abstract eat(str) //定义一个抽象方法,抽象方法不允许具有任何内容
sayHi(){ //抽象类可以包含实例方法
console.log(`Hi,I am ${this.name}`)
}
}
//定义一个子类继承自抽象类
class Dog1 extends Animal1{
eat(str){ //必须定义抽象方法的实例方法,否则报错
console.log(`${this.name} like to eat ${str}`)
}
}
let dog0 = new Animal1('Jack') //报错
let dog1 = new Dog1('Jack',2)
dog1.eat('bone') //Jack like to eat bone
dog1.sayHi() //Hi,I am Jack