11 - TS class的补充
类的定义与使用
// 定义一个Point类,拥有x和y两个属性,可以通过构造函数进行初始化,并拥有一个add方法可以进行点的加法操作
class Point {
x: number;
y: number;
// 构造函数,用于初始化对象
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
// 成员函数,用于实现点的加法操作
public add(p: Point): Point {
return new Point(p.x + this.x, p.y + this.y);
}
}
// 创建一个Point对象,并调用其add方法
const p = new Point(0, 0);
const newP = p.add(new Point(1, 1));
console.log(newP);
成员函数的重载
// Point类,除了基本属性和方法外,增加了成员函数的重载功能
class Point {
// ...
// 重载的add方法,可以接受两个数字或一个Point对象作为参数
public add(x: number, y: number): Point;
public add(p: Point): Point;
public add(x: number | Point, y?: number) {
if (typeof x === 'number') {
return new Point(this.x + x, this.y + y!);
}
const p = x;
return new Point(this.x + p.x, this.y + p.y);
}
}
// 使用重载的add方法
const p = new Point(0, 0);
const newP = p.add(new Point(1, 1));
console.log(newP);
Getter和Setter
// C类,展示了getter和setter的使用
class C {
_length = 0;
// 使用getter获取属性值
get length() {
return this._length;
}
// 使用setter设置属性值
set length(value) {
this._length = value;
}
}
// 个人建议的实现方式,使用方法代替getter和setter
class C {
_length = 0;
getLength() {
return this._length;
}
setLength(value) {
this._length = value;
}
}
索引器
// Arr类,展示了索引器的使用
class Arr<T> {
[i: number]: T;
}
const a = new Arr<number>();
a[10] = 100;
console.log(a[10]);
类型继承与类的继承
// 接口的继承
interface BasicAddress {
name?: string;
street: string;
city: string;
country: string;
postalCode: string;
}
interface AddressWithUnit extends BasicAddress {
unit: string;
}
// 类的继承
class Animal {
move() {
console.log("Moving along!");
}
}
class Dog extends Animal {
woof(times: number) {
for (let i = 0; i < times; i++) {
console.log("woof!");
}
}
}
// 使用组合和接口代替继承
interface Movable {
move(): void;
}
class Dog implements Movable {
move() {
console.log('move dog');
}
}
// 使用泛型进行继承
class Movable<T extends Animal> {
animal: T;
move() {
console.log(`${this.animal.getName()} is moving`);
}
}
成员可见域
// 展示public、private和protected三种成员可见域的使用
// 使用public
class Point {
x: number;
}
// 使用private
class Point {
private x: number;
constructor() {
this.x = x; // 可以在类内部访问
}
getX() {
return this.x;
}
}
const p = new Point();
// console.log(p.x); // Error: Property 'x' is private and only accessible within class 'Point'.(2341)
关于`protected`关键字
// `protected` 允许在当前类和它的继承类中访问成员。
class Animal {
private _name1; // 私有成员,只能在本类中访问
protected _name2; // 受保护的成员,可以在子类中访问
}
class Dog extends Animal{
getName1(){
return this._name1 // Error: 不能在子类中访问父类的私有成员
}
getName2(){
return this._name2 // 正确: 可以在子类中访问父类的受保护成员
}
}
静态成员
class MyClass {
static x = 0; // 静态属性
static printX() { // 静态方法
console.log(MyClass.x); // 访问静态属性
}
}
console.log(MyClass.x); // 访问静态属性
MyClass.printX(); // 调用静态方法
静态成员和类的实例没有关系,静态成员、静态方法都绑定在类型本身上。
静态成员继承
class Base {
static getGreeting() {
return "Hello world"; // 静态方法返回字符串
}
}
class Derived extends Base {
myGreeting = Derived.getGreeting(); // 子类继承父类的静态方法
}
特殊的静态成员名称
class S {
static name = "S!";
// Error : 静态属性'name'与'Function.name'的构造函数内置属性冲突。
}
注意:`name`是Function的一个内置属性,因此在类中定义静态属性`name`会导致错误。
为什么没有静态类?
// 在Java中有静态类,但在JS中,由于类的嵌套和B包的逻辑,逻辑过于复杂,不适合增加嵌套类访问外部类成员的逻辑。
class A {
x : number
foo(){
const y = 0
class B{
bar(){
this.x // Error: 属性 'x' 在类型 'B' 上不存在
console.log(y)
}
}
return B
}
}
类型守卫
class FileSystemObject {
isFile(): this is FileRep {
return this instanceof FileRep; // 判断当前实例是否是FileRep的实例
}
isDirectory(): this is Directory {
return this instanceof Directory; // 判断当前实例是否是Directory的实例
}
isNetworked(): this is Networked & this {
return this.networked; // 判断当前实例是否有networked属性
}
constructor(public path: string, private networked: boolean) {}
}
class FileRep extends FileSystemObject {
constructor(path: string, public content: string) {
super(path, false);
}
}
class Directory extends FileSystemObject {
children: FileSystemObject[];
}
interface Networked {
host: string;
}
const fso: FileSystemObject = new FileRep("foo/bar.txt", "foo");
if (fso.isFile()) {
fso.content; // 类型守卫确保此处fso是FileRep类型
} else if (fso.isDirectory()) {
fso.children; // 类型守卫确保此处fso是Directory类型
} else if (fso.isNetworked()) {
fso.host; // 类型守卫确保此处fso是Networked类型
}
抽象类
// 抽象类不可以实例化
abstract class Base {
abstract getName(): string;
printName() {
console.log("Hello, " + this.getName()); // 调用子类实现的getName方法
}
}
const b = new Base(); // Error: 不能创建抽象类的实例
// 必须被继承并实现抽象方法
class Derived extends Base {
getName() {
return "world"; // 实现父类的抽象方法
}
}
const d = new Derived();
d.printName(); // 输出: Hello, world
类型的关系
// TS会通过成员去判断两个类型是否一致
class Point1 {
x = 0;
y = 0;
}
class Point2 {
x = 0;
y = 0;
}
// 正确: Point1和Point2的结构一致
const p: Point1 = new Point2();
另一个例子:
class Person {
name: string;
age: number;
}
class Employee {
name: string;
age: number;
salary: number;
}
// 正确: Employee具有Person的所有属性,因此它们是兼容的
const p: Person = new Employee();
最后一个例子:
class Empty {}
function fn(x: Empty) {
// x是一个空的类型,所以不能做任何事情
}
// 都是正确的!
fn(window);
fn({});
fn(fn);
浙公网安备 33010602011771号