# 面向对象

## 类：class

```typescript
class Person {

    // 静态属性
    static readonly lang: string = "chinese";

    // 静态只读属性，类似const
    static readonly happy: boolean = true;

    // 成员属性/实例属性
    name: string = "孙悟空";

    // 成员属性没有默认值
    age: number;

    // 只读成员属性
    readonly sex: string;

    // 所有属性必须初始化，无论是不是只读属性，而java中只有只读属性(final)才必须初始化
    // 这是构造器，构造器不可以重载
    constructor(age: number, sex: string) {
        this.age = age; // this指代当前对象
        this.sex = sex;
    }

    // 静态方法
    static sayHello() {
        console.log("hello");
    }

    // 成员方法
    printHello() {
        console.log("hello");
    }
}

// 根据类创建对象
const p = new Person(10, "男");
// 访问静态属性
console.log(Person.lang);
// 访问静态方法
Person.sayHello()
// 访问成员属性
console.log(p.age)
// 访问成员方法
p.printHello()
```

## 封装

```typescript
class Person {
    // 下划线是内置命名，但是无法放置其他程序访问
    // 他会与get/set配合
    // private代表私有属性
    private _name: string;
    private _age: number;
    // public代表公开属性
    public happy: boolean = true;
  
  	// 还有一个protected属性，只可以被子类使用
  	// private 不能被子类使用

    constructor(name: string, age: number) {
        this._name = name;
        this._age = age;
    }

    // 提供 getter/setter 获取内部属性，这些方法默认为public的
    get name(): string {
        return this._name;
    }

    set name(value: string) {
        this._name = value;
    }

    get age(): number {
        return this._age;
    }

    set age(value: number) {
        if (value < 0 || value > 120) {
            throw new Error("年龄不能小于0大于120");
        }
        this._age = value;
    }
}

// 通过get/set访问属性
let p: Person = new Person("张三", 18);

// 可以直接通过.的方式访问变量的get/set方法
console.log(p.name); // 访问 _age 的get方法
p.age = -1; // 访问 _name 的set方法
```

执行结果：

```
                throw new Error("年龄不能小于0大于120");
                ^

Error: 年龄不能小于0大于120
    at Person.set (/Users/yangsx/Project/temp/nots-ts/src/a.js:25:23)
    at Object.<anonymous> (/Users/yangsx/Project/temp/nots-ts/src/a.js:38:7)
    at Module._compile (node:internal/modules/cjs/loader:1095:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:816:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12)
    at node:internal/main/run_main_module:17:47
```

> 解决不可以使用get 和 set的问题：tsc -t es5 a.ts

### public、protected、private

* `public`，都可以访问
* `protected`是提供给子类访问的，外部不可访问
* `private`是私有的，只有自己内部可以访问

### 属性快速写法

下面两种写法是等同的：

```typescript
class Person {
    private _name:string;
    private _age: number;
    
    constructor(name: string, age: number) {
        this._name = name;
        this._age = age;
    }
}
```

```typescript
class Person {

    constructor(private name: string, private age: number) {
    }
    
}
```

## 继承

```typescript
class Animal {
    protected _name: string;

    constructor(name: string) {
        this._name = name;
    }

    public sayHello(): void {
        console.log("动物叫~")
    }
}

class Dog extends Animal {
}

class Cat extends Animal 
}

// 子类继承了父类的所有非私有方法和属性，包括构造器
let d: Dog = new Dog("旺财");
let c: Cat = new Cat("猫大姐");
```

### 多继承：不支持

不支持多继承。

### 子类新增方法

给狗增加跑的方法：

```typescript
class Dog extends Animal {
    public run():void {
        console.log(`${this._name}在跑~`)
    }
}
d.run(); // dog类对象才能调用run
```

### 方法重写

```typescript
class Dog extends Animal {
    public run():void {
        console.log(`${this._name}在跑~`)
    }
    
    override sayHello() {
        console.log("汪汪");
    }
}

class Cat extends Animal {
    override sayHello() {
        console.log("喵喵");
    }
}
```

### super关键字

```typescript
class Cat extends Animal {
    override sayHello() {
        super.sayHello(); // 先调用父类的sayHello方法
        console.log("喵喵");
    }
}
```

### 构造器重写

```typescript
class Cat extends Animal {
    constructor() {
        super("猫大姐"); // 必须调用父类的构造
    }

    override sayHello() {
        super.sayHello(); // 必须先调用父类的sayHello方法，不写不可
        console.log("喵喵");
    }
}
let c: Cat = new Cat();
```

## 抽象类

抽象类不可以用于创建实例。抽象类中可以定义抽象方法，抽象方法没有方法体，且必须必须被重写：

```typescript
abstract class Animal { 
    protected _name: string;

    constructor(name: string) {
        this._name = name;
    }

    public abstract sayHello(): void;
}

class Dog extends Animal {
    public run(): void {
        console.log(`${this._name}在跑~`)
    }

    sayHello() { // 因为是抽象方法，override可以省略
        console.log("汪汪");
    }
}

class Cat extends Animal {
    constructor() {
        super("猫大姐"); // 必须调用父类的构造
    }

    override sayHello() { 
        super.sayHello(); // 先调用父类的sayHello方法
        console.log("喵喵");
    }
}
```

## 接口

```typescript
// 接口不仅可以定义方法，还可以定义属性
interface A {
    name: string;
    age: number;

    sayHello(): void;
}

interface B {}

// 实现接口
// 接口可以多实现
class B implements A, B {
    age: number;
    name: string;

    constructor(age: number, name: string) {
        this.age = age;
        this.name = name;
    }

    sayHello(): void {
        console.log(`hello ${this.name}`)
    }

}
```

### 函数式接口

```javascript
interface Action {
    (event: string): void
}
transition: function (event: string, action: Action) {
	action()
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yangsx95.gitbook.io/notes/programming-language/typescript/mian-xiang-dui-xiang.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
