面向对象之 class(下)

四种成员可见性

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

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

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

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

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

static 属性与 static block

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

1
2
3
4
5
6
7
8
9
10
11
class Dog {
static kind = "狗";

constructor() {
// ...
}
}

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

注意:用 static 声明的属性,其名称不能是 nameprototypelengthargumentscaller 其中之一

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

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

1
2
3
4
5
6
7
8
9
10
class Foo {
static #count = 0;
static {
const count = loadFromLocalStorage() || 0;
Foo.#count += count;
}
constructor() {
console.log(Foo.#count);
}
}

类与泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 赋值给一个变量

1
2
3
4
5
6
7
const Rectangle = class {
constructor(public height: number, public width: number) {}
area() {
return this.height * this.width;
}
};
const r = new Rectangle(100, 200);

抽象类(不常用)

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

抽象类不允许被实例化

1
2
3
4
5
6
7
8
abstract class Base {
abstract getName(): string;
printName() {
console.log('Hello, ' + this.getName());
}
}
const b = new Base();
// ^--- 报错:Cannot create an instance of an abstract class

抽象类中的抽象方法必须被子类实现,之后才可进行实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
abstract class Base {
abstract getName(): string;
printName() {
console.log('Hello, ' + this.getName());
}
}
class Derived extends Base {
getName() {
return 'world';
}
}
const d = new Derived();
d.printName();

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

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

把类当作参数(常用)

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

1
2
3
4
5
6
7
8
9
10
11
12
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')); // 报错
1
2
3
4
5
6
7
8
9
10
11
12
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')); // 报错

(●'◡'●)ノ♥