概述
面向对象思想:这也不是一朝一夕建立起来的
基础部分,学习类的时候,仅仅讨论新增的语法部分。
进阶的时候再讨论 抽象类 等等。
新增的类语法
- TS不允许动态的给对象添加属性,要求使用 属性列表(name: string) 来描述类中的属性!
- 属性列表也不存在于编译结果中!
- 防止在属性列表中声明属性却没在constructor中初始化的情况
- 配置:”strictPropertyInitialization”: true,//更加严格的方式检查属性是否进行了初始化
- 属性的初始化位置
- 构造函数中
- 属性默认值(可以在属性列表里设置默认值,也可以在构造函数的参数中使用默认值写法)
- 属性可以是可选的 ?: 也可以是只读的 readonly
- 我不希望类外面能访问到我的属性, JS怎么做? Symbol; TS呢?—>添加访问修饰符,有三种
- public:默认的访问修饰符,公开的,所有的代码均可访问
- private:私有的,只有在 类里面 可以访问
- protected:暂时不讲,todolist
- 语法糖:属性简写
- 如果某个属性,通过构造函数的参数传递,并且加上了修饰符(只读或者访问修饰符均可)且不做任何处理的赋值给该属性,则可以进行简写 ```typescript constructor(public name: string, readonly age: number){
}
```typescript
class User {
readonly id: number;//不能改变
name: string;
age: number;
gender: '男' | '女' = '男';
pid ?: string;
//我不希望外面能访问到这两个属性, js怎么做? Symbol; TS呢?-->添加访问修饰符
private publishNumber: number = 5;//每天最多发布的文章数量
private curNumber: number = 0;//当前发布的文章数量,
constructor(name: string, age: number, gender:'男'|'女', readonly what: string = 'whatever', pid?: string,){
this.name = name;//报错,为啥。因为TS不允许动态的在对象中添加属性
this.age = age;
// this.gender = gender;
// this.pid = pid;
this.id = Math.random();
console.log(this.curNumber);
}
publish(title: string){
if(this.curNumber < this.publishNumber){
console.log('发布一篇文章', title);
this.curNumber++;
}else{
console.log('今日发布文章数量已上限.');
}
}
}
const u = new User('aa', 2, '女', );
u.name = '2341';
u.age = 324;
// u.gender = '男';
console.log(u);
u.publish('title1');
访问器
比如:要对年龄的值要进行控制不能为负吧,不能大的离谱吧。
我们希望用函数来控制,这是最合适的。
Java中就是用 setName; getName ,JS也可以这样,这样需要调用函数
但是js有这个对应的语法糖,set name; get name;故ts也可以使用,也会在编译结果中出现,都是函数
注意:setter getter中用变量的时候不能出现 this.name 否则陷入无限递归,应该用this._name
这个就相当于是setter和getter,u.name会自动调用get name 而u.name = ‘wjw’;就会自动调用set name
练习:增加洗牌和发牌功能
用类改造扑克牌程序(在接口改造的基础上)
//发牌: 发完牌后,有四个card的数组,按斗地主来 17 17 17 3
dealCards():[Card[], Card[], Card[], Card[]]{
const res: [Card[], Card[], Card[], Card[]] = [[],[],[],[]];
return res;
}
上述看着挺烦的,那怎么改造呢?Card[]就是一叠牌Deck
import { Mark, Color } from "./enums";
import { Card, Joker } from "./types"
interface DealCardsResult {
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 'joker'
}
}
this.cards.push(joker);
joker = {
type: 'big',
getString() {
return 'JOKER';
}
}
this.cards.push(joker);
}
//洗牌
shuffle() {
const len = this.cards.length;
for (let i = 0; i < len; i++) {
const targetIndex = this.getRandomNum(0, this.cards.length);
[this.cards[i], this.cards[targetIndex]] = [this.cards[targetIndex], this.cards[i]];
}
}
//发牌: 发完牌后,有四个card的数组,按斗地主来 17 17 17 3
// dealCards(): [Card[], Card[], Card[], Card[]] {
// const res: [Card[], Card[], Card[], Card[]] = [[], [], [], []];
// return res;
// }
dealCards(): DealCardsResult {//这里可以直接使用这个问下下定义的类Deck
const player1: Deck = this.takeCards(17);
const player2: Deck = this.takeCards(17);
const player3: Deck = this.takeCards(17);
const left: Deck = this.takeCards(3);
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);//如果不断言,有可能是undefined,就会报错!
}
return new Deck(cards);//我给你的牌, 拿好
}
//无法取到最大值,最多是max-1
private getRandomNum(min: number, max: number) {
const sub = max - min;
return Math.floor(Math.random() * sub + min);
}
print() {
this.cards.forEach((card, i) => {
let str = card.getString();
console.log(str);
if ((i + 1) % 4 === 0) {
console.log('\n');
}
});
}
}