typescript – class

作者 : admin 本文共5483个字,预计阅读时间需要14分钟 发布时间: 2024-06-9 共1人阅读

class

类的定义

虽然JavaScript语言支持了类,但是本质上是函数,类是一种语法糖,typescript语言对于JavaScript的类进行了拓展,为其添加了类型支持。类的定义有两种方式:1. 类声明 2. 类表达式

类声明

class ClassName {
    // ...
}

在该语法中,class是关键字,ClassName表示类的名称,在类的声明中类名是必选的

class Circle {
    radius: number
}
const c = new Circle()

类声明不会提升,因此必须先声明后使用,在使用类声明的时候,不允许声明同名的类,否则将产生错误

类表达式

类表达式是一种定义类的方式

const Name = class ClassName {
    //...
}

在这个语法中,class是关键字,Name表示引用了该类的变量名

const Circle = class {
    radius: number
}
const a = new Circle()

如果在类表达式中定义了类名,则该类名只能在类内部使用,在类外不允许使用该类名

const A = class B {
    name = B.name
}
const b = new B()

成员变量

在类中定义成员变量的方法如下

class Circle {
    raduis: number = 1
}
class Circle_a {
    radius: number ;
    constructor() {
        this.radius = 1        
    }
}

在此例中,在构造函数中将radius成员变量的值初始化为1, 同时注意,在构造函数中引用成员变量的时候需要使用this关键字。

readonly属性

添加readonly属性的时候,能够将该成员变量声明为只读的,只读变量必须在声明的时候初始化或者构造在函数里面

class A {
    readonly a = 0;
    readonly b: number;
    readonly c: number; // error
    constructor () {
        this.b = 0 
    }
}

成员函数

成员函数也称为方法,声明成员函数在与对象字面量中的声明方法是类似的。

class Circle {
    radius: number = 1;
    area() :number {
        return 1
    }
}

成员存取器

成员存取器由get和set方法构成,并且会在类中声明一个属性。

class C {
    private _foo: number;
    get foo() {
        return this._foo
    }
    set foo(value: number) {
        
    }
}

如果有一个类属性同时定义了get方法和set方法,那么get方法和set方法中必须具有相同的可访问性。
存取器是实现数据封装的一种方式,提供了一层额外的访问控制。类可以将成员变量的访问权控制在类的内部,在类的外部通过存取器方法来间接的访问成员变量。

索引成员

类的索引成员会在类的类型中引入索引签名,索引签名必须包含两种,分别为字符串签名和数值索引签名。类中所有的属性和方法必须符合字符串索引签名定义的类型。

class A {
    x: number = 0
    [prop: string]: number;
    [prop: number]: number;
}

在类的索引上不允许定义可访问修饰符

成员可访问性

  • public
    类的公有成员没有访问限制,可以在当前类的内部,外部以及派生类的内部访问,类的公有成员使用public修饰符,在默认情况下,类的所有成员都是公有成员,因此,在定义公有成员的时候也可以定义public修饰符
  • protected
    类的受保护成员允许在当前类的内部和派生类的内部访问,但是不允许在当前类的外部访问,类的受保护成员使用protected修饰符表示。
  • private
    类的私有成员只允许在当前类的内部进行访问,在当前类的外部以及派生类的内部不允许进行访问,类的私有成员使用private修饰符标识
  • 私有字段
    在字段标识符前面添加一个#符号,不论是在定义私有字段还是在访问私有字段的时候,都不要在私有字段名字前面添加一个#符号
class Circle {
    #radius: number;
    constructor() {
        this.#radius = 1
    }
}
const circle = new Circle();
circle.#radius ; // 不允许被访问

构造函数

构造函数用于创建和初始化类的实例,当使用new运算符调用一个类的时候,类的构造函数就会被调用,构造函数以constructor作为函数名

class Circle {
radius: number;
constructor(r: number) {
this.radius = r;
    }
}
const c = new Circle(1);

和普通函数相同,在构造函数中也可以定义可选参数,默认值参数和剩余参数,但是构造函数中不允许定义返回值类型,因为构造函数的返回值类型永远为类的实例类型。

class A {
    constructor(a: number = 0, b ?: boolean, ...c: string[]) {
        
    }
}
class B {
    constructor(): object{} // 编译错误,不允许指定构造函数的返回值类型
}

在构造函数上可以使用可访问性修饰符,允许使用该类型来创建实例对象,在默认的情况下,构造函数是公有的,如果将构造函数设置成为私有的,只允许在类的内部创建该类的对象。

class Singleton {
    private static instance?: Singleton;
    private constructor() {
        if (!Singleton.instance) {
            Singleton.instance = new Singleton()
        }
        return SIngleton.instance
    }
}
new Singleton()

与函数重载类型,构造函数也支持重载,将没有函数体的构造函数声明为构造函数重载,同时定义了函数体的构造函数声明称为构造函数实现。

class A {
    constructor(x: number, y: number) ;
    constructor(s: string);
    constructor(xs: number | string, y?: number) {}
}
const a = new A(0, 0)
const b = new A('foo')

参数成员

typescript提供了一种简洁语法能够把构造函数的形式参数声明为类的成员变量,称为参数变量,在构造函数类型列表中,为形式参数添加了一个可访问性修饰符或者readonly修饰符,该形式参数就成了参数成员,进而会被声明为类的成员变量

class A {
    constructor(public x: number) {}
}
const a = new A(0)
a.x // 0

继承

继承是面向对象程序设计的三个基本特征之一,typescrpt中的类也支持继承,在定义了id时候可以使用extends关键字来指定要继承的类

class DerivedClass extends BaseClass {}

BaseClass称为基类, DerivedClass称为派生类。派生类继承了基类。派生类继承了基类的非私有成员。
在派生类中,可以通过super关键字来访问基类中的非私有成员。在派生类中只能通过super关键字来访问积累中的菲斯有成员,无法使用this关键字来引用积累中的非私有成员。
若是派生类重写了基类中的受保护成员,则可以将该成员的可访问性设置为受保护的或者公有的。
在派生类的构造函数中必须使用super()语句就能调用积累的构造函数

class Circle extends Shape {
    radius: number;
    constructor() {
        super();
        this.radius = 1
    }
}

实例化派生类时的初始化顺序如下

  1. 初始化基类的属性
  2. 调用基类的构造函数
  3. 初始化派生类的属性
  4. 调用派生类的构造函数
    typescript中的类仅仅支持单继承,不支持多继承,在extends语句中只能指定一个基类
class A {}
class B {}
class C extends A, B {}

typescript 允许接口继承类,若接口继承了一个类,那么该接口会继承积累中所有成员的类型。
在接口继承类的时候,接口不但回家i成积累的公有成员类型,还会继承类的受保护成员类型和私有成员类型,如果接口从积累继承了非公有成员,那么接口只能由积累或者积累的子类来实现。

class A {
    x: string = ''
    y(): boolean {
        return true
    }
}
declare const b: B
b.x 
b.y()
class A implenments I {
    private x: string = ''
    protected y: string = ''
}
// 接口能够继承a的私有属性和受保护属性
interface I extends A {}
class B extends A implements I {}
class C implements I {} // c不是a的子类,无法实现a的私有属性和受保护属性。 

实现接口

如果类的定义中声明了要实现的接口,那么这个类就需要实现接口中定义的类型成员。

interface A{}
interface B{} 
class C implements A, B {}

静态成员

类的定义中可以包含静态成员,类的静态成员不属于类的某个实例,而是属于类本身,类的静态成员需要使用static关键词定义,并且只允许通过类名来访问。

class Circle {
    static version: string = '1.0'
}
const version = Circle.version
circle .version  // version是Circle类的静态属性

类的静态成员也可以定义不同的可访问性,比如public,private和protected
类的pulic静态成员对访问没有限制,可以在当前类的内部,外部以及派生类的内部访问
类的protected静态成员允许在当前类的内部和派生类的内部访问,但是不允许在当前类的外部访问
类的private静态成员只允许在当前类的内部访问
类的public静态成员和protected静态成员也可以被继承。

class Base {
    public static x: string = ''
    protected static y: string = ''
}
class Derived extends Base {
    b() {
        Derived.x;// 继承了基类的静态成员x
        Derived.y;// 继承了基类的静态成员y
    }
}

抽象类和抽象成员

abstract class A {}

抽象类不能被实例化,也就是说,不允许使用new运算符来创建一个抽象类的实例。抽象类主要是作为基类使用,派生类可以继承抽象类。
抽象类可以继承其他抽象类。

abstract class Base{}
abstract class Derived extends Base {}

在此例中,基类和派生类都是抽象类,不能被实例化。抽象类允许包含抽象成员,也允许包含非抽象成员。

abstract class Base {
    abstract a: string;
    b: string = ''
}

在抽象类中声明抽象成员,抽象成员不允许包含具体实现代码。如果一个具体类继承了抽象类,在具体的派生类中必须实现抽象类基类中的所有抽象成员,因此抽象类中的抽象成员能不能声明为private,否则将无法在派生类中实现该成员。

abstract class Base {
    abstract a: string;
    abstract get accessor(): string;
    abstract set accessor(value: string);
    abstract methond(): boolean;
}
class Derived extends Base {
    a: string = 'd';
    private _accessor: string = '';
    get accessor(): string {
        return this._accessor
    }
    set accessor(value: string) {
        this._accessor = value
    }
    method(): boolean {
        return true
    }
}

this类型

在类中存在一种特殊的this类型,表示当前this值的类型,我们可以在类的非静态成员的类型注解中使用this类型,

class Counter {
    private count: number = 0;
    public add(): this {
        this.count++;
        return this
    }
    public subtrace(): this{
        this.count--;
        return this
    }
    public getResult():number {
        return this.count
    }
}
const counter = new Counter();
counter.add().add().substarct().getResult()

this类型是动态的,表示当前this值的类型,当前this值的类型不一定是引用了this类型的那个类,该差别主要是体现在类之间有继承关系的时候

class A {
    foo(): this {
        return this;
    }
}
class B extends A {
    bar(): this {
        return this
    }
}
const b = new B();
const x = b.bar().foo() // 类型为B

this类型不允许应用于类的静态成员

class A {
    static a : this; // 编译错误,this类型只能用于类的非静态成员
}

类类型

class A {
    static x : number = 0;
    y: number = 0;
}
const a: A = new A() // 类类型,即实例类型
interface AConstructor {
    new (): A;
    x: number;
}
const b: AConstructor = A  // 类构造函数类型
本站无任何商业行为
个人在线分享 » typescript – class
E-->