ts 学习笔记 - 类

[TOC]typescript

类的概念

  • 类 (class) : 定义了意见事物的抽象特色,包含它的属性和方法
  • 对象 (Object) :类的实例,经过 new 生成
  • 面对对象 (OOP) 的三大特性: 封装、继承、多态
  • 封装 (Encapsulation):将对数据的操做细节隐藏起来,值暴露对外的接口。外界调用端不须要(也不可能)知道细节,就能经过对外提供的接口来访问该对象,同时也保证了外界没法任意更改对象内部的数据
  • 继承 (Inheritance): 子类继承父类, 子类除了拥有父类的全部特性外, 还有一些更具体的特性
  • 多态 (Polymorphism):由继承二产生了相关的不一样的类,对同一个方法能够有不一样的响应。好比 CatDog 都是继承自 Animal, 可是分别实现了本身的 eat 方法。此时针对某一个实例,咱们无需了解它是 Cat 仍是 Dog, 就能够直接调用 eat 方法, 程序会自动判断出来应该如何执行 eat
  • 存取器 (getter & setter):用来改变属性的读取和赋值行为
  • 修饰符 (Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。好比 public 表示公有属性或方法
  • 抽象类(Abstract Class):抽象类是供其余类继承的基类,抽象类不容许被实例化。抽象类中抽象方法避税在子类中被实现
  • 接口(Interfaces):不一样类之间公有的属性或方法,能够抽象成一个接口。接口能够被类实现(implements)。一个类只能继承自另外一个类, 可是能够实现多个接口

类的用法

属性和方法

使用 class 定义类, 使用 constructor 定义构造函数。函数

经过 new 生成新实例的时候, 会自动调用构造函数。this

class Animal {
  constructor(name) {
    this.name = name
  }
  sayHi() {
    return `My name is ${this.name}`
  }
}

let a = new Animal('jack')
console.log( a.sayHi() ) // My name is Jack

类的继承

使用 extends 关键字实现继承, 子类中使用 super 关键字来调用父类的构造函数和方法。spa

class Cat extends Animal {
  constructor(name) {
    super(name) // 调用父类的 constructor(name)
    console.log(this.name)
  }
  sayHi() {
    return 'Meow, ' + super.sayHi() // 调用父类的 sayHi()
  }
}
let c = new Cat('Tom') // Tom
console.log(c.sayHi()) // Meow, My name is Tom

存取器

使用 getter 和 setter 能够改变属性的赋值和读取行为:3d

class Animal {
  constructor(name) {
    this.name = name
  }
  
  get name() {
    return 'Jack'
  }
  set name(value) {
    console.log('setter: ' + value)
  }
}
let a = new Animal('Kitty'); // setter: Kitty
a.name = 'Tom'; // setter: Tom
console.log(a.name); // Jack

静态属性

到目前为止,咱们只讨论了类的实例成员,哪些仅当类被梳理化的时候才会被初始化的属性。code

使用 static 修饰符修饰的方法称为静态方法,它们不须要实例化,而是直接经过类来调用。对象

下例中,咱们实现一个网格类, 经过 calculateDistanceFromOrigin 方法来当前点计算到原点的距离。继承

class Grid {
  static origin = { x: 0, y: 0 }
  
  scale: number
  
  constructor(scale: number) {
    this.scale = scale
  }
  
  calculateDistanceFromOrigin(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
  }
}
let grid1 = new Grid(1.0) // scale => 1
let grid5 = new Grid(5.0) // scale => 5

grid1.calculateDistanceFromOrigin({x: 3, y: 4}) 
grid5.calculateDistanceFromOrigin({x: 3, y: 4})

Typescript 中的用法

public, private, protected接口

Typescript 中可使用三种访问修饰符(Access Modifiers),分别是 public, private, protectedip

  • public 修饰的属性或方法都是公有的, 在任何地方均可以访问到。默认的全部属性和方法都是 public 的 。
  • private 修饰的属性或方法都是私有的,不能再申明它的类的外部去访问。
  • protected 修饰的属性或方法是受保护的,它和 private 相似, 区别是它的子类中也是容许被访问。

🌰

class Person {
  public name
  public constructor(name) {
    this.name = name
  }
}

let p = new Person('Jack')
console.log(p.name) // Jack
p.name = 'Tom'
console.log(p.name) // Tom

上面的例子中 name 被设置了 public , 因此直接访问 name 是被容许的。

不少时候,咱们但愿有的属性是没法在外部直接存取。 这时候就须要用到 private

class Person {
  private name
  constructor(name) {
    this.name = name
  }
}

let p = new Person('Jack')
console.log(p.name) // Jack
p.name = 'Tom' // err Property 'name' is private...

使用 private 修饰的属性或方法,在子类中也是不容许访问的:

class Person {
  private name
  constructor(name) {
    this.name = name
  }
}

class Male extends Person {
  constructor(name) {
    super(name)
    console.log(this.name)
  }
}

// err

须要注意的是,TypeScript 编译以后的代码中,并无限制 private属性在外部的可访问性。

而若是是用 protected 修饰, 怎容许在子类中访问:

class Animal {
    protected name;
    public constructor(name) {
        this.name = name;
    }
}

class Cat extends Animal {
    constructor(name) {
        super(name);
        console.log(this.name);
    }
}

抽象类

abstract 用于定义抽象类和其中的抽象方法。

什么是抽象类?

首先抽象类不容许实例化,

abstract class Persong {
  public name
 	public constructor(name) {
    this.name = name
  }
  public abstract sayHi()
}

let p = new Person('Jack') // err

上面的例子中,咱们定义了一个抽象类 Animal,而且定义了一个抽象方法 sayHi。在实例化抽象类的时候报错了。

其次,抽象类中的抽象方法必须被子类实现:

abstract class Person {
 	constructor(name) {
    this.name = name
  }
  public abstract sayHi()
}

class Male extends Persong {
    public eat() {
        console.log(`${this.name} is eating.`)
    }
}

let Jack = new Male('jack') // err Male 中 并无实现 Perosn 中的 sayHi 方法

上例中因为 Male 中没有实现 父类 Person 中的 sayHi 方法, 因此 编译报错

abstract class Person {
 	constructor(name) {
    this.name = name
  }
  public abstract sayHi()
}

class Male extends Persong {
    public sayHi() {
        console.log(`Meow, My name is ${this.name}`)
    }
}
let Jack = new Male('jack')  // success

类的类型

类的类型 与接口类似

class Person {
	name: sting
  constructor(name: sting) {
    this.name = name
  }
  sayHi(): string {
    return `My name is ${this.name}.`
  }
}

let p: Person = new Person('Jack')
console.log(a.sayHi()) // My name is Jack

类与接口

类实现接口

实现(implements)是面对对象中一个很重要的概念。通常来说,一个类只能继承自另一个类,有的时候不一样类之间存在着一些能够共用的特性,这时能够把这些特性提取成接口 (interfaces),用 implements 关键字来实现。

举例来讲,门是一个类, 防盗门是门的子类。若是防盗门有报警功能, 这时咱们能够简单的给防盗门添加一个报警的方法。这时候若是有另外一类, 车。 车子也须要有报警功能。此时就能够考虑吧报警器这个功能提取出来, 做为一个接口,防盗门和车都去实现它。

interface Alarm {
  alert()
}

class Door {
  
}

class SecurityDoor extends Door implements Alarm {
  alert() {
    console.log('SecurityDoor alert')
  }
}

class Car implements Alarm {
  alert() {
    console.log('Car alert')
  }
}

一个类能够实现多个接口:

interface Alarm {
  alert()
}

interface Light {
    lightOn()
    lightOff()
}

class Car implements Alarm, Light {
    alert() {
        console.log('Car alert')
    }
    lightOn() {
        console.log('Car light on')
    }
    lightOff() {
        console.log('Car light off')
    }
}

上面的例子中, Car 实现了 Alarm, Light 接口, 既能报警, 也能开关车灯。

接口继承接口

接口与接口之间能够是继承关系:

经过使用 extends 来继承

interface Alarm {
  alert()
}

interface Light extends Alarm {
    lightOn()
    lightOff()
}

class Car implements Light {
    alert() {
        console.log('Car alert')
    }
    lightOn() {
        console.log('Car light on')
    }
    lightOff() {
        console.log('Car light off')
    }
}

接口继承类

接口也能够继承类:

class Point {
  x: number
  y: number
}

interface Point3D extends Poing {
  z: number
}

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

##混合类型

咱们知道,可使用接口的方式来定义一个函数须要符合的形状:

interface SearchFunc {
    (source: string, subString: string): boolean
}

let mySearch: SearchFunc
mySearch = function(source: string, subString: string) {
    return source.search(subString) !== -1
}

有时候,一个函数还能够有本身的属性和方法:

interface Counter {
    (start: number): string
    interval: number
    reset(): void
}
    
function getCounter(): Counter {
    let counter = <Counter>function (start: number) { }
    counter.interval = 123
    counter.reset = function () { }
    return counter
}

let c = getCounter()
c(10)
c.reset()
c.interval = 5.0
相关文章
相关标签/搜索