[TOC]typescript
类
类的概念
- 类 (class) : 定义了意见事物的抽象特色,包含它的属性和方法
- 对象 (Object) :类的实例,经过
new
生成 - 面对对象 (OOP) 的三大特性: 封装、继承、多态
- 封装 (Encapsulation):将对数据的操做细节隐藏起来,值暴露对外的接口。外界调用端不须要(也不可能)知道细节,就能经过对外提供的接口来访问该对象,同时也保证了外界没法任意更改对象内部的数据
- 继承 (Inheritance): 子类继承父类, 子类除了拥有父类的全部特性外, 还有一些更具体的特性
- 多态 (Polymorphism):由继承二产生了相关的不一样的类,对同一个方法能够有不一样的响应。好比
Cat
和Dog
都是继承自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
, protected
。ip
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