面向对象之 class(下)

四种成员可见性

public(类外可见)public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public

private(类内可见)private 修饰的属性或方法是私有的,不能在声明它的类的外部访问

protected(子类可见)protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的

#var(真私有属性) 上面的都是 TS 的语法(访问修饰符),而 #var 是 JS 的语法,在属性名前面加上 # 即可做到真正的属性私有

注意:由于 private 是 TS 的语法,在类型被擦除后就没了;真正的私有属性得使用 # 才能做到

static 属性与 static block

我们可以使用 static 来定义一个静态属性,静态属性只能通过类名来访问

ts
class Dog {
  static kind = "狗";

  constructor() {
    // ...
  }
}

const dog = new Dog();
console.log(dog.kind); // undefined
console.log(Dog.kind); // "狗"

注意:用 static 声明的属性,其名称不能是 name、prototype、length、arguments、caller 其中之一

因为 js 中的类都是通过函数来模拟的

static block 主要用来初始化私有属性(类外部无法初始化私有属性)

ts
class Foo {
  static #count = 0;
  static {
    const count = loadFromLocalStorage() || 0;
    Foo.#count += count;
  }
  constructor() {
    console.log(Foo.#count);
  }
}

类与泛型

ts
class Hash<K, V> {
  map: Map<K, V> = new Map();
  set(key: K, value: V) {
    this.map.set(key, value);
  }
  get(key: K) {
    return this.map.get(key);
  }
}

class Hash<K, V> extends Map<K, V> {
  destroy() {
    this.clear();
  }
}

class 表达式

将匿名的 class 赋值给一个变量

ts
const Rectangle = class {
  constructor(public height: number, public width: number) {}
  area() {
    return this.height * this.width;
  }
};
const r = new Rectangle(100, 200);

抽象类

abstract 用于定义抽象类和其中的抽象方法

ts
abstract class Base {
  abstract getName(): string;
  printName() {
    console.log('Hello, ' + this.getName());
  }
}
const b = new Base();
//            ^--- 报错:Cannot create an instance of an abstract class

抽象类:

  • 不能被直接实例化:new Base() ❌ 会报错
  • 必须通过子类继承实现
  • 可以包含具体实现(如 printName() 方法)
  • 可以定义抽象方法

抽象方法:

  • 只有声明,没有实现(没有方法体,比如 getName())
  • 强制子类必须实现这些方法
  • 定义核心接口,确保子类行为一致性
ts
abstract class Base {
  abstract getName(): string;
  printName() {
    console.log('Hello, ' + this.getName());
  }
}
class Derived extends Base {
  // 强制实现 getName
  getName() {
    return 'world';
  }
}
const d = new Derived();
d.printName();

可以看出,抽象类是介于 interface 和 class 之间的一种写法

如果一个 class 中的属性全都是抽象属性,那么也可以直接把这个 class 当作 interface

把类当作参数(常用)

注意是把类作为参数,而不是把类的实例化对象作为参数

ts
class Person {
  constructor(public name: string) {}
  sayHi() {
    console.log(`Hi, I am ${this.name}`);
  }
}
function greet(constructor: typeof Person) {
  const p = new constructor('ClariS');
  p.sayHi();
}
greet(Person); // 不报错
greet(new Person('ClariS')); // 报错
ts
class Person {
  constructor(public name: string) {}
  sayHi() {
    console.log(`Hi, I am ${this.name}`);
  }
}
function greet(constructor: new (name: string) => Person) {
  const p = new constructor('ClariS');
  p.sayHi();
}
greet(Person); // 不报错
greet(new Person('ClariS')); // 报错
浅尝类型体操
面向对象之 class(上)

评论区

评论加载中...