初识Typescrip(二)

一、类

// 使用class关键字来定义一个类
class Person {
  // 定义实例属性, 通过实例进行访问person.name
  name: string = 'jack'

  // 在属性前使用 static 关键字可以定义类属性(静态属性)直接通过类名进行访问Person.age
  static age: number = 18
 
  // 以 readonly 开头的属性不可被修改 
  readonly gender: string = 'Male'

 // 定义方法, 同样可以使用 static 关键字修饰
  sayHi() {
    console.log('Hi')
  }
}

const person = new Person()
person.gender = "Female" // 报错: 无法分配到"gender", 因为它时一个只读属性
// 使用 abstract 关键字修饰的类表示抽象类,不能用来创建对象,是专门用来被继承的类 
abstract class Animal {
  name: string
  constructor(name: string) { 
    this.name = name
  }
  
  /*
  * 1. 通过 abstract 关键字修饰的方法为抽象方法,没有方法体
  * 2. 抽象方法只能在抽象类中定义
  * 3. 子类必须对父类中所定义的抽象方法进行重写
  */
  abstract eat():void
}

// Cat类继承Animal类, 通过继承可以拥有父类的所有属性和方法
class Cat extends Animal {
  age: number
  constructor(name: string, age: number) {
    // 如果在子类中写构造函数,在子类的构造函数中必须对父类构造函数进行调用
    super(name) // 使用super函数对父类的构造函数进行调用
    this.age = age
  }
  
  // 子类中添加同父类一样的方法,则子类方法会覆盖父类的方法
  eat() {
    // super.eat() 子类中同样可以使用super关键字调用父类的方法
    console.log(2)
  }
}

class Dog extends Animal {} //报错,没有对父类中的抽象方法进行重写
const animal = new Animal() //报错,无法创建抽象类的实例
const cat = new Cat('cat', 18)
console.log(cat) // {name: "cat", age: 18}
cat.eat() // 重写父类eat的方法,因此输出结果为 2

二、接口

/*
* 使用接口来定义一个类的结构,用来定义类中包含哪些属性和方法
* 同时接口也可以当作类型声明去使用
*/
interface customize {
  name: string
  age: number
}

interface customize {
  gender: string
}

const obj: customize = {
    name: 'jack',
    age: 18
} // 报错,同名接口相当于是将里面定义的所有属性进行了合并,这里缺失了gender属性

const obj: customize = {
    name: 'jack',
    age: 18,
    gender: '男' // 成功
} 

/*
* 接口可以在定义类的时候去限制类的结构
* 接口所有的方法都是抽象方法
*/
interface customize {
  name: string
  hello() {} // 报错,接口中的所有属性不能有实际值,它只是定义了对象的结构,而不考虑实际值
} 

interface customize {
  name: string
  hello(): void // 成功
} 

/*
* 定义一个类时,可以使类去实现一个接口,实现接口就是使类满足接口的要求
* 接口和抽象类的不同点:
*   1. 抽象类中可以有抽象方法也可以有普通方法,但接口只能是抽象方法
*   2. 用抽象类的时候使用的是extends关键字,而定义一个接口的时候使用的是implements关键字
*/
class Person implements customize {
  name: string
  constructor (name: string) {
    this.name = name
  }
  hello() {
    console.log(`${this.name} say Hello`)
  }
}

三、属性的封装

class Person  {
  /*
  * 1.public修饰的属性可以在任意位置访问、修改 默认值
  * 2.private 私有属性 只能在类内部进行访问、修改
  * 3.protected 受保护的类,只能在当前类和当前类的子类中访问、修改
  */
  private _name: string
  private _age: number
  constructor (name: string,age: number) {
    this._name = name
    this._age = age
  } 
  // 定义方法来获取name属性
  getName() {
    return this._name //私有属性可以通过添加方法使私有属性能够被外部访问
  }
  
  // 定义方法来设置name属性
  setName(value: string) {
    this._name = value
  }
  
  // getter、setter简写形式 
  get age() {
    console.log('age的值被读取!')
    return this._age
  }
  
  set age(value: string) {
    console.log('age的值被修改')
    this._age = value
  }  
}

const person = new Person('jack', 19)
console.log(person._name) //报错 私有属性,只能在Person类中访问

person.setName('pink') //通过调用setName修改name属性值
console.log(person.getName()) // pink 通过调用getName获取私有属性值

person.age = 20
console.log(person.age) // 20
// 可以直接将属性定义在构造函数中
class Person  {
  constructor (public name: string, public age: number) {} 
}

// 等同于
class Person  {
  name: string
  age: number
  constructor (name: string, age: number) {
    this.name = name
    this.age = age
  } 
}

四、泛型

// 在定义函数或者类时,遇到类型不明确的情况下可以使用泛型
function fn<T>(a: T): T { // 表示 a 的类型为T
  return a
}

fn(10) // 不指定泛型,TS自动推断类型
fn<string>('jack') // 指定泛型

interface customize {
  name: string
}

// T extends customize 表示泛型T必须是customize实现类
function fn1<T extends customize>(a: T): string{
  return a.name
}

const result = fn1({name: 'jack'})
console.log(result) // jack

// 在类当中也可以使用泛型
class Person<T> {
  // 定义了一个属性name,其类型为T
  name: T
  constructor(name: T) {
    this.name = name
  }
}

const person = new Person<string>('jack')
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值