类
传统的 JavaScript 使用函数和基于原型的继承来创建可重用的组件。
function Point (x, y) {
this.x = x
this.y = y
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')'
}
var p = new Point(1, 2)
从 ES6 开始,我们能够使用基于类的面向对象的方式。
class Point {
constructor (x, y) {
this.x = x
this.y = y
}
toString () {
return `(${this.x}, ${this.y})`
}
}
TypeScript 除了保留了 ES6 中类的功能以外,还增添了一些新的功能。
class Dog {
constructor (name: string) {
this.name = name
}
name: string
run () {}
}
class Husky extends Dog {
constructor (name: string, color: string) {
super(name)
this.color = color
}
color: string
}
上面的例子中需要注意以下几点:
- 继承类中的构造函数里访问
this
的属性之前,一定要调用super
方法; - TypeScript 和 ES6 中,“类的成员属性”都是实例属性,而不是原型属性,“类的成员方法”都是“原型”方法。
Dog.prototype
=>{constructor: ƒ, run: ƒ}
,new Dog('huang')
=>{name: "huang"}
- TypeScript 中实例的属性必须有初始值,或者在构造函数中被初始化。
public、private、protected、readonly
TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public
、private
和 protected
-
public
修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是public
-
private
修饰的属性或方法是私有的,不能在声明它的类的外部访问,包括继承它的类也不可以访问 -
protected
修饰的属性或方法是受保护的,它和private
类似,区别是它在子类中也是允许被访问 -
以上三种可以修饰构造函数,默认为
public
,当构造函数为private
时,该类不允许被继承或实例化;当构造函数为protected
时,该类只允许被继承。 -
readonly
修饰的属性为只读属性,只允许出现在属性声明或索引签名中。
public
公共修饰符
class Animal {
public name: string
public constructor (name: string) {
this.name = name
}
}
let a = new Animal('Jack')
console.log(a.name) // Jack
a.name = 'Tom'
console.log(a.name) // Tom
private
私有修饰符
class Animal {
private name: string
public constructor (name: string) {
this.name = name
}
}
let a = new Animal('Jack')
console.log(a.name) // Error: Property 'name' is private and only accessible within class 'Animal'.
class Cat extends Animal {
constructor (name: string) {
super(name)
console.log(this.name) // Error: // Property 'name' is private and only accessible within class 'Animal'.
}
}
需要注意的是,TypeScript 编译之后的代码中,并没有限制 private
属性在外部的可访问性。
上面的例子编译后的代码如下:
var Animal = (function () {
function Animal (name) {
this.name = name
}
return Animal
}())
var a = new Animal('Jack')
console.log(a.name)
protected
受保护修饰符
class Animal {
protected name: string
public constructor (name: string) {
this.name = name
}
}
class Cat extends Animal {
constructor (name: string) {
super(name)
console.log(this.name)
}
}
:::tip
构造函数参数添加修饰等同于在类中定义该属性,这样使代码更为简洁。
:::
class Animal {
// public name: string
constructor (public name: string) {
this.name = name
}
}
class Cat extends Animal {
constructor (public name: string) {
super(name)
}
}
let a = new Animal('Jack')
console.log(a.name) // Jack
a.name = 'Tom'
console.log(a.name) // Tom
readonly
只读修饰符
class Animal {
readonly name: string
public constructor (name: string) {
this.name = name
}
}
let a = new Animal('Jack')
console.log(a.name) // Jack
a.name = 'Tom' //Error: Cannot assign to 'name' because it is a read-only property.
注意如果 readonly
和其他访问修饰符同时存在的话,需要写在其后面。
class Animal {
// public readonly name: string
public constructor (public readonly name: string) {
this.name = name
}
}
抽象类
abstract
用于定义抽象类和其中的抽象方法。需要注意以下两点:
抽象类不允许被实例化
abstract class Animal {
public name: string
public constructor (name: string) {
this.name = name
}
}
var a = new Animal('Jack') //Error: Cannot create an instance of an abstract class.
抽象类中的抽象方法必须被继承类实现
abstract class Animal {
public name: string;
public constructor (name: string) {
this.name = name;
}
abstract sayHi (): any
}
class Cat extends Animal {
public color: string
sayHi () { console.log(`Hi`) }
constructor (name: string, color: string) {
super(name)
this.color = color
}
}
var a = new Cat('Tom', 'Blue')