回顾 ES6 的 Class

  1. 缺少类型检查,user 里面的 nameage 可以随便的传值,虽然可以用 setget 来进行限制;但是如果定义的一个类中,除了构造函数外 (假设有100个需要类型检查的属性值),那里面岂不是全是 getset

  2. 哪些属性是 Class 私有的、只读的,哪些是公开的呢? 虽然可以使用 es6 里面的 symbol(符号) 来定义私有的,但是有点麻烦;

  3. 代码提示不是很友好 *(vscode 有代码提示,往往都要开发者记忆类里面的关键词)*等;

// 定义一个用户的类,里面有两个属性,名字和年龄
class User {
    constructor(name, age) {
        this.sex = "男";
        this.id = Math.random().toString(32).substr(-6);
        this.name = name;
        this.age = age;
    }
    getAge() {
        return this.age;
    }
    static getNumber() {
        return '1';
    }
}

const u = new User(123, 12);
console.log(u.getAge()); // 123

console.log(User.getNumber()); // 1

TypeScript 的 Class

属性的初始化检查

tsconfig.json 中添加一个配置 strictPropertyInitialization: true,则属性初始化要赋值,否则会报错;

class User {
    readonly id: number // 不能改变
    gender: "男" | "女" = "男"  // gender: "男" | "女" // 属性“gender”没有初始化表达式,且未在构造函数中明确赋值
    pid?: string

    constructor(public name: string, private _age: number) {
        this.id = Math.random();
    }
}

const u = new User("aa", 22);

属性简写

如果某个属性,通过构造函数的参数传递,并且不做任何处理的赋值给该属性,可以进行简写;

// 简写前
class User {
  name: string
  age: number
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

// 简写后
class User {
  constructor(public name: string, public age: number) {
  }
}

访问器

TypeScript
TypeScript
// 第一种:类似 Java 的形式
class User {
    name: string
    age: number
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    setName(value: string) {
        this.name = value; // 这里可以对名字做业务处理
    }
    getName() {
        return this.name;
    }
}

const u = new User('cll', 12);
u.name = 'cll123'; // 设置值
console.log(u.name); // 获取值
// 第二种:es6+
class User {
    _name: string
    age: number
    constructor(name: string, age: number) {
        this._name = name;
        this.age = age;
    }
    set name(value: string) {
        this._name = value; // 这里可以对名字做业务处理
    }
    get name() {
        return this._name;
    }
}

const u = new User('cll', 12);
u.name = 'cll123';
console.log(u.name);

属性修饰符

  1. readonly: 只读的,写在属性,方法等的前面;

  2. public: 公共的,写在属性,方法等的前面,ts 默认的都是所有的属性是公开的;

  3. protected: 受保护的,写在属性,方法等的前面,在类、子类里面可以访问,在类外部没法访问;

  4. private: 私有的,写在属性,方法等的前面,标记改属性或者方法只能在类中使用;

class User {
    readonly id: string;     // 定义只读属性
    name: string;
    age?: number;            // 定义可选属性
    sex: "男" | "女" = "男";  // 初始化赋值

    constructor(name: string, age: number) {
        this.id = Math.random().toString(32).substr(-6);
        this.name = name;
        this.age = age;
    }

    // 定义私有的函数
    private getAge(): number {
        return this.age as number;
    }
}

隐式实现同名接⼝

  1. 类隐式地实现了⼀个与它同名的接⼝,并且

    1. 该接⼝被声明为 MyClass.prototype 的类型;
    2. 该接⼝可以被重复声明,且⽤户声明的成员不强制要求在类声明块中实现;
interface MyClass {
    c: string;
}

class MyClass {
    a: string;
    b: string;
}

MyClass.prototype.c = 'abc';

this 指向约束

TS 中 this 的问题

  1. 对象里面的 this 推断

  2. 类中的 this 推断

解决 TS 中 this 的问题

  1. 配置 noImplicitThis: true 不允许 this 隐式的指向 any,手动声明该函数中 this 的指向,解决了 对象里面的 this 问题

  2. 手动声明该函数中 this 的指向,将 this 作为函数的第一个参数,该参数只用于约束 this,并不是真正的参数,也不会出现在编译结果中,解决了 类中的 this 问题

案例:增加洗牌和发牌功能

TypeScript
TypeScript
TypeScript
TypeScript
// enums.ts
export enum Color {
    heart = "♥",
    spade = "♠",
    club = "♣",
    diamond = "♦"
}

export enum Mark {
    A = "A",
    two = "2",
    three = "3",
    four = "4",
    five = "5",
    six = "6",
    seven = "7",
    eight = "8",
    nine = "9",
    ten = "10",
    eleven = "J",
    twelve = "Q",
    king = "K"
}
// types.ts
import { Color, Mark } from "./enums";

export interface Card {
    getString(): string
}

export interface Joker extends Card {
    type: "big" | "small"
}
// deck.ts
import { Card, Joker } from "./types";
import { Mark, Color } from "./enums";

interface PublishResult {
    player1: Deck,
    player2: Deck,
    player3: Deck,
    left: Deck
}

export class Deck {
    private cards: Card[] = [];

    constructor(cards?: Card[]) {
        if (cards) {
            this.cards = cards;
        } else {
            this.init();
        }
    }

    private init() {
        const marks = Object.values(Mark);
        const colors = Object.values(Color);
        for (const m of marks) {
            for (const c of colors) {
                this.cards.push({
                    color: c, mark: m,
                    getString() {
                        return this.color + this.mark;
                    }
                } as Card);
            }
        }
        let joker: Joker = {
            type: "small",
            getString() {
                return "jo";
            }
        }
        this.cards.push(joker);
        joker = {
            type: "big",
            getString() {
                return "JO"
            }
        }
        this.cards.push(joker);
    }

    print() {
        let result = "\n";
        this.cards.forEach((card, i) => {
            result += card.getString() + "\t";
            if ((i + 1) % 6 === 0) {
                result += "\n";
            }
        })
        console.log(result);
    }

    /***
    * 洗牌
    */
    shuffle() {
        // [x1,x2,x3,x4,x5,x6,x7]
        for (let i = 0; i < this.cards.length; i++) {
            const targetIndex = this.getRandom(0, this.cards.length);
            const temp = this.cards[i];
            this.cards[i] = this.cards[targetIndex];
            this.cards[targetIndex] = temp;
        }
    }

    //发完牌后,得到的结果有4个card[]
    publish(): PublishResult {
        let player1: Deck, player2: Deck, player3: Deck, left: Deck;
        player1 = this.takeCards(17);
        player2 = this.takeCards(17);
        player3 = this.takeCards(17);
        left = new Deck(this.cards);

        return { player1, player2, player3, left };
    }

    private takeCards(n: number): Deck {
        const cards: Card[] = [];
        for (let i = 0; i < n; i++) {
            cards.push(this.cards.shift() as Card);
        }
        return new Deck(cards);
    }

    /***
    * 无法取到最大值
    * @param min 
    * @param max 
    */
    private getRandom(min: number, max: number) {
        const dec = max - min;
        return Math.floor(Math.random() * dec + min);
    }
}
// index.ts
import { Deck } from "./deck";

const deck = new Deck();
deck.shuffle();
console.log("=========洗牌之后=======");
deck.print();
const result = deck.publish();
console.log("=========发牌之后=======");

console.log("===========玩家1========");
result.player1.print();

console.log("===========玩家2========");
result.player2.print();

console.log("===========玩家3========");
result.player3.print();

console.log("===========桌面========");
result.left.print();
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 回顾 ES6 的 Class
  2. 2. TypeScript 的 Class
    1. 2.1. 属性的初始化检查
    2. 2.2. 属性简写
    3. 2.3. 访问器
    4. 2.4. 属性修饰符
    5. 2.5. 隐式实现同名接⼝
  3. 3. this 指向约束
    1. 3.1. TS 中 this 的问题
    2. 3.2. 解决 TS 中 this 的问题
  4. 4. 案例:增加洗牌和发牌功能