在属性前使用static关键字可以定义类属性(静态属性)
直接定义的属性是实例属性,需要通过per对象的实例去访问
static开头的静态属性,可以直接通过类去访问
//使用class关键字来定义一个类
class Person{
//定义属性
name:string = "天海";
//在属性前使用static关键字可以定义类属性(静态属性)
static age: number = 18;
}
const per = new Person();
//直接定义的属性是实例属性,需要通过per对象的实例去访问
console.log(per);
console.log(per.name);
per.name = "天海一直在";
//static开头的静态属性,可以直接通过类去访问
console.log(Person.age);
只读属性,不能修改
readonly name:string = "天海";
此例中constructor为构造函数
在构造函数中当前对象就是当前新建的那个对象
案例:
class Hero{
na : string;
level : number;
constructor(na:string,level:number){
//在实例方法中,this就表示当前的实例,可以通过this向新建的对象中添加属性
this.na = na;
this.level = level;
}
choose(){
//在方法中通过this来表示当前调用方法的对象
console.log("您选择了" + this.na);
}
}
const kasa = new Hero('卡莎',5);
const mow = new Hero('牛头',5);
kasa.choose()
//输出:您选择了卡莎
class 子类 extends 父类{}
使用继承后,子类会拥有父类所有的方法和属性
案例:
(function (){
//定义一个英雄类
class Hero{
name:string;
level:number;
constructor(name:string,level:number){
this.name = name;
this.level = level;
}
levelup(){
this.level += 1
console.log("我现在" + this.level + "级" );
}
}
class ADC extends Hero{
shanxian(){
console.log(`${this.name}有闪现`);
}
}
class Support extends Hero{
}
const kasa = new ADC('卡莎',1);
const niutou = new Support('牛头',2);
console.log(kasa);
kasa.levelup();
kasa.shanxian();
console.log(niutou);
niutou.levelup();
})();
注:如果在子类中添加了和父类相同的方法,则子类方法会覆盖掉父类方法——方法的重写
运行结果:
在类的方法中,super就表示当前类的父类
(function(){
class Hero{
name:string;
constructor(name:string){
this.name = name;
}
shanxian(){
console.log('我有闪现');
}
}
class ADC extends Hero{
level:number;
constructor(name:string,level:number){
super(name);
this.level = level
}
shanxian() {
super.shanxian();
console.log('是否使用闪现');
}
}
const kasa = new ADC('卡莎',3);
kasa.shanxian();
})()
和其他类区别不大,知识不能用来创建对象。
抽象类就是专门用来被继承的类。
不能使用这个类创建对象
abstract class xxx{}
抽象方法: abstract 方法名():void;
抽象方法只能定义在抽象类中
子类必须对抽象方法进行重写,也就是说被继承后的方法是失效的
接口中的所有的属性都不能有实际值,只定义对象的结构,接口内所有方法都是抽象方法。
(function(){
//描述一个对象的类型
type heroType = {
name:string,
level:number
};
/* 接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法
同时接口也可以当初类型声明去使用
可以重复声明
*/
interface myInterface{
name:string;
age:number;
}
const myInterface = {
name:'kasa',
level:18
}
})()
定义类时,可以使类去实现一个接口
使类满足接口的要求
下方代码中,设置了英雄的名称为私有方法,不可以修改,而等级是可以被修改的。
(function(){
class Hero{
//公用属性:public修饰的属性可以在任意位置访问。
//私有属性:private智能在类内部进行访问。
private name:string;
public level:number;
constructor(name:string,level:number){
this.name = name;
this.level = level;
}
}
const per = new Hero('孙悟空',16);
//name行报错
per.name = '贾克斯';
//level行可以通过编译
per.level = -5;
console.log(per);
})();
但这就出现了问题,英雄等级为负值了,而且英雄的名称即不能被修改也不能被读取到。
我们不允许这种情况发生,所以可以通过getter和setter方法来获取属性并设置条件。
(function(){
class Hero{
//都设为私有属性
private name:string;
private level:number;
constructor(name:string,level:number){
this.name = name;
this.level = level;
}
//属性的存取器,getter用于读取属性,setter用来设置属性
getName(){
return this.name;
}
getLevel(){
return this.level
}
setLevel(value:number){
if(value>=0 && value<=18){
this.level = value;
}
}
}
const per = new Hero('孙悟空',15);
//获取并修改属性
per.getLevel()
per.setLevel(12);
console.log(per);
})();
同样的方法,TS提供了get和set关键字
注:方法名和属性名不能重复,这里用 _name和 _level来写方法。
(function(){
class Hero{
private name:string;
private level:number;
constructor(name:string,level:number){
this.name = name;
this.level = level;
}
//Ts中设置getter方法的方式
get _name(){
return this.name
}
get _level(){
return this.level
}
set _level(value){
if(value>=0 && value<=18){
this.level = value;
}
}
}
const per = new Hero('孙悟空',15);
per.getLevel()
per.setLevel(12);
console.log(per);
})();
protected:受包含的属性,只能在当前类和当前类的子类中访问(对继承有效)
class A {
protected num:number;
constructor(num:number){
this.num=num;
}
}
class B extends A{
test(){
console.log(this.num);
}
}
最后再说明一下定义类的简化写法
class C{
constructor(public name:string,public level:number){
}
}
const c = new C('xxx',111)
console.log(c);
在定义函数或类时,遇到类型不明确就可以使用泛型
function fn<T>(a:T):T{
return a;
}
//调用具有泛型的函数
不指定泛型,TS自动推断
fn(10)
//指定泛型
fn<string>('hello')
可以同时指定多个
function fn2<T,K>(a:T,b:K):T{
console.log(b);
return a;
}
fn2<number,string>(123,'hello');
泛型T作为借口的子类
interface Inter{
length:number;
}
function fn3<T extends Inter>(a:T):number{
return a.length
}