TypeScript 学习(三)

333 阅读3分钟

仓库地址:github.com/YaliixxG/Ty…

  1. 引用类的成员时,需要加this
  2. 我们使用 new 构造了 Greeter 类的一个实例。 它会调用之前定义的构造函数,创建一个 Greeter 类型的新对象,并执行构造函数初始化它。 示例:
class Greeter {
  //属性
  greeting: string

  //构造函数
  constructor(message: string) {
    this.greeting = message
  }

  //方法
  greet() {
    return "Hello," + this.greeting
  }
}

let greeter = new Greeter("world")

简单的继承示例:

class Animal {
  move(distanceInMeters: number = 0) {
    console.log(`Animal moved ${distanceInMeters}米`)
  }
}
class Dog extends Animal {
  bark() {
    console.log("wang!wang!")
  }
}
const dog = new Dog()
dog.bark()
dog.move(10)

复杂一点得继承示例:

class Animal {
  name: string
  constructor(theName: string) {
    this.name = theName
  }
  move(distanceInMeters: number = 0) {
    console.log(`${this.name} moved ${distanceInMeters}米`)
  }
}

class Snake extends Animal {
  // 子类包含一个构造函数,必须调用 super(),它会执行基类的构造函数。在构函数访问this的属性之前,一定要调用super()。这是TypeScript强制执行的一条重要规则。
  constructor(name: string) {
    super(name)
  }
  move(distanceInMeters = 45) {
    console.log("蛇...")
    super.move(distanceInMeters) //访问类属性前,需调用super,这里重写了从基类继承来的move方法,使得具有不同的功能
  }
}

class Horse extends Animal {
  constructor(name: string) {
    super(name)
  }
  move(distanceInMeters: number = 35) {
    console.log("马...")
    super.move(distanceInMeters)
  }
}

let sam = new Snake("sammy the Python")
let tom: Animal = new Horse("Tommy the Palomino")

sam.move()
tom.move(34) //这里tom声明使Animal类型,但是值为Horse,调用tom.move时,会调用Horse里重写的方法

//输出:
// 蛇...
// Sammy the Python moved 5m.
// 马...
// Tommy the Palomino moved 34m.

静态属性

创建类的静态成员,这些属性存在于类本身上面而不是类的实例上。
static定义静态属性,如果要访问静态属性的话,前面必须加上类名(与访问实例属性上加this一样)

class Grid {
  static orgin = { x: 0, y: 0 } // static定义orgin这个静态属性
  abc:(point:{x:number,y:number}){
    //这里访问静态属性时,在属性前加上类名的前缀
    let xDist = (point.x - Grid.origin.x)
    let yDist = (point.y - Grid.origin.y)
    return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale
  }
  constructor(public scale: number) //这里构造函数里面是定义的实例参数,用到实例属性的时候,前面是加 this 的前缀
}

let grid1 = new Grid(1.0);  // 1x scale
let grid2 = new Grid(5.0);  // 5x scale

console.log(grid1.abc({x: 10, y: 10}));
console.log(grid2.abc({x: 10, y: 10}));

抽象类

  1. 关键字 abstract 定义抽象类和在抽象类内部定义抽象方法
  2. 抽象类中的方法,不包含具体实现,只能在派生类(子类)实现
  3. 抽象类定义方法和接口类似,只定义方法签名,不包含具体方法体
  4. 抽象方法必须包含 abstract 关键字并且可以包含访问修饰符
  5. 抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化,直接实例化会报错
abstract class A {
  constructor(public name: string) {}

  //普通定义方法,包括具体实现,访问实例属性用this
  printName(): void {
    console.log("名字:" + this.name)
  }

  //抽象类方法,必须有关键字 abstract ,并且不包含具体实现,只能在派生类实现
  abstract printMeeting(): void
}

//作为抽象类 A 的派生类 B 登场

class B extends A {
  constructor() {
    //在派生类的构造函数必须调用super()
    super("LALALALLALA")
  }

  printMeeting(): void {
    console.log("这是基类A定义的抽象类方法,在派生类B的实现")
  }

  hello(): void {
    console.log("这是没有在基类A定义的方法,只是派生类B定义的普通方法")
  }
}

let a: A // 允许创建一个抽象类型的引用
a = new A() //报错!不能创建一个抽象类的实例,直接实例化报错
a = new B() // 允许对一个抽象子类进行实例化和赋值
a.printName() //这是抽象类 A里面定义的普通方法
a.printMeeting() //这是调用抽象类 A 里面定义的抽象类方法
a.hello() //报错! 这个方法抽象类A中并没有定义,所以引用报错

高级技巧

构造函数

class Greeter {
  greeting: string
  constructor(message: string) {
    this.greeting = message
  }
  greet() {
    return "hello," + this.greeting
  }
}
let greeter: Greeter //这样写是表明Greeter类的实例的类型是 Greeter
greeter = new Greeter("world")
console.log(greeter.greet())

把类当做接口使用

类定义会创建两个东西:类的实例类型和一个构造函数。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。(有点不明白 = =)

class Point {
  x: number
  y: number
}

interface Point3d extends Point {
  z: number
}

let point3d: Point3d = { x: 1, y: 2, z: 3 }