提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过
ES6class
关键字,可以定义类。基本上,ES6 的 class
可以看作只是一个语法糖
,它的绝大部分功能,ES5 都可以做到,新的 class
写法只是让对象原型的写法更加清晰、更像面向对象
编程的语法而已。上面的代码用 ES6 的 “类” 改写
JavaScript写法
//定义类 JavaScript写法
classPerson {
constructor (name:string,age:number,sub:boolean) {
this.name=name
this.age=age
this.sub=sub
}
}
newPerson("小满",22,false)
TypeScript写法
//在TypeScript中是需要提前声明类型的
classPerson {
name:string
age:number
sub:boolean//没错,没使用标红的是这些
constructor (name:string,age:number,sub:boolean) {
this.name=name
this.age=age
this.sub=sub//上面定义了变量就需要使用,如果没用使用的话声明的变量就会标红(就算不标红不提示,真运行下去也会报错),不能就那么放着,要么就用上,要么就给他个默认值0塞着
}
}
newPerson("小满",22,false)
public
public内部外部都可以访问,如果定义了public,像p就能够访问constructor内部的变量了。当然,默认情况下也是public
//在TypeScript中是需要提前声明类型的
classPerson {
publicname:string
publicage:number
publicsub:boolean//没错,没使用标红的是这些
constructor (name:string,age:number,sub:boolean) {
this.name=name
this.age=age
this.sub=sub//上面定义了变量就需要使用,如果没用使用的话声明的变量就会标红(就算不标红不提示,真运行下去也会报错),不能就那么放着,要么就用上,要么就给他个默认值0塞着
}
}
letp=newPerson("小满",22,false)
p.agep.namep.sub//都可以访问
private
private 私有变量只能在内部访问
//在TypeScript中是需要提前声明类型的
classPerson {
privatename:string
privateage:number
privatesub:boolean//没错,没使用标红的是这些
constructor (name:string,age:number,sub:boolean) {
this.name=name
this.age=age
this.sub=sub//上面定义了变量就需要使用,如果没用使用的话声明的变量就会标红(就算不标红不提示,真运行下去也会报错),不能就那么放着,要么就用上,要么就给他个默认值0塞着
}
}
letp=newPerson("小满",22,false)
p.agep.namep.sub//都访问不到了
protected
protected内部和子类中访问
provate跟protectd他们的区别是一个是只能在内部使用,一个是内部与子类访问,例子如下
//在TypeScript中是需要提前声明类型的
classPerson {
protectedname:string
privateage:number
publicsub:boolean//没错,没使用标红的是这些
constructor (name:string,age:number,sub:boolean) {
this.name=name
this.age=age
this.sub=sub//上面定义了变量就需要使用,如果没用使用的话声明的变量就会标红(就算不标红不提示,真运行下去也会报错),不能就那么放着,要么就用上,要么就给他个默认值0塞着
}
}
classManextendsPerson{
constructor(){
super("小满",22,false)
this.name
this.sub//这两个都可以访问到,this.age访问不到。因为age是private,private只能在内部使用而不能在子类访问,Man是Person的子类
}
}
letp=newPerson("小满",22,false)
p.agep.namep.sub
static 静态属性 和 静态方法
- 静态属性和非静态属性的区别:
- 在内存中存放的位置不同:所有 static 修饰的属性和方法都存放在内存的方法区里,而非静态的都存在堆内存中
- 出现的时机不同:静态属性和方法在没创建对象之前就存在,而非静态的需要在创建对象才存在
- 静态属性是整个类都公用的
- 生命周期不一样,静态在类消失后被销毁,非静态在对象销毁后销毁
- 用法:静态的可以直接通过类名访问,非静态只能通过对象进行访问
- 使用
static
注意事项
- 带静态修饰符的方法只能访问静态属性
- 非静态方法既能访问静态属性也能访问非静态属性
- 非静态方法不能定义静态变量
- 静态方法不能使用 this 关键字
- 静态方法不能调用非静态方法,反之可以
- 父子类中静态和非静态的关系
- 对于非静态属性,子类可以继承父类非静态属性,但是当父子类出现相同的非静态属性时,不会发生子类的重写并覆盖父类的非静态属性,而是隐藏父类的非静态属性
- 对于非静态方法,子类可以继承并重写父类的非静态方法
- 对于静态属性,子类可以继承父类的静态属性,但是如何和非静态属性一样时,会被隐藏
- 对于静态方法,子类可以继承父类的静态方法,但是不能重写静态方法,同名时会隐藏父类的
- 注:静态属性、静态方法、非静态属性都可以被继承和隐藏,但是不可以被重写,非静态方法可以被重写和继承
- 静态代码块的作用:一般情况下,有些代码需要在项目启动的时候就执行,这时候就需要静态代码块,比如一个项目启动需要加载配置文件,或初始化内容等。
- 静态代码块不能出现在任何方法体内对于普通方法:普通方法是需要加载类 new 出一个实例化对象,通过运行这个对象才能运行代码块,而静态方法随着类加载就运行了。对于静态方法:在类加载时静态方法也加载了,但是必须需要类名或者对象名才可以访问,相比于静态代码块,静态方法是被动运行,而静态代码块是主动运行
- 静态代码块不能访问普通变量普通变量只能通过对象调用的,所以普通变量不能放在静态代码块中。
普通代码块和构造代码块
- 静态代码块和构造代码块在声明上少一个 static 关键字
- 执行时机:构造代码块在创建对象时被调用,每次创建对象都会调用一次,且优先于构造函数执行。注:不是优先于构造函数执行,而是依托于构造函数,如果不创建对象就不会执行构造代码块
- 普通代码块和构造代码块的区别在于,构造代码块是在类中定于的,而普通代码块是在方法体中定义的,执行顺序和书写顺序一致。
执行顺序
静态代码块 > 构造代码块 > 构造函数 > 普通代码块
classPerson {
protectedname:string
privateage:number
publicsub:boolean//没错,没使用标红的是这些
staticaaa:string='123456'//静态属性
constructor (name:string,age:number,sub:boolean) {
this.name=name
this.age=age
this.sub=sub//上面定义了变量就需要使用,如果没用使用的话声明的变量就会标红(就算不标红不提示,真运行下去也会报错),不能就那么放着,要么就用上,要么就给他个默认值0塞着
this.run()//会报错,调用不了。互斥的,不能够通过静态函数去访问内部的变量,或者是在内部的变量去调用外部的静态函数
Person.run()//只能这样去调用
}
staticrun (){
this.dev()//静态函数之间可以互相调用
this.aaa//用this的话只能访问上面static类型的,其他的不管是public还是private或者是protected都是不能够访问的(会报不存在属性的错误) 因为这里的this指的是当前这个类,而构造函数里面的this指的是新的实例对象
return'789'
}
staticdev(){
this.aaa//静态函数之间可以互相调用
return'dev'
}
}
console.log(Person.run())//返回789
Person.aaa//能够直接访问,不需要再new一下
console.log(Person.aaa)
letp=newPerson("小满",22,false)
interface 定义 类
ts interface 定义类 使用关键字 implements 后面跟 interface 的名字多个用逗号隔开 继承还是用 extends
通过接口去约束类
interfacePerson{
run(type:boolean):boolean
}
classManimplementsPerson{//会提示我们Man中缺少属性run,但类型Person中需要该属性
}
//通过接口去约束类
interfacePerson{
run(type:boolean):boolean
}
interfaceH{
set():void
}
classManimplementsPerson,H{//会报错,提示我们缺少set属性
run(type:boolean):boolean{
returntype
}
}
interfacePerson{
run(type:boolean):boolean
}
interfaceH{
set():void
}
classA{//也可以使用继承去使用
params:string
constructor(params){
this.params=params
}
}
classManextendsAimplementsPerson,H{
run(type:boolean):boolean{
returntype
}
set(){
//啥也没有,这就是用接口去描述类
}
}
抽象类(TypeScript8)
用关键词
abstract
修饰的类称为 abstract 类(抽象类)应用场景如果你写的类实例化之后毫无用处此时我可以把他定义为抽象类
或者你也可以把他作为一个基类 -> 通过继承一个派生类去实现基类的一些方法
对于 abstract 方法只允许声明,不允许实现(因为没有方法体)(毕竟叫抽象,当然不能实实在在的让你实现),并且不允许使用 final 和 abstract 同时修饰一个方法或者类,也不允许使用 static 修饰 abstract 方法。也就是说,abstract 方法只能是实例方法,不能是类方法。
abstractclassA{
name:string
construct(name:string){//construct:构造器
this.name=name
}
//abstract getName(){//方法getName不能具有实现,因为它标记为抽象。定义抽象类的函数
// return 213
//}
setName(name:string){
this.name=name
}
abstractgetName():string//抽象类
}
classBextendsA{//派生类。定义了抽象类必须在派生类里实现
//B类是继承A类的,此时A类就是一个抽象类
constructor(){
super('小满')
}
getName():string{
returnthis.name
}
}
//此时A类是无法被创建实例的(new A),也就是无法创建抽象类的实例
//B类是可以创建实例的(new B)
letb=newB
b.setName("小满2")//通过抽象类的设置,成功修改掉子类的内容
// setName(name:string){
// this.name = name
// }
console.log(b.getName())