类的继承
在 TypeScript 里,我们可以使用常用的面向对象模式。 基于类的程序设计中一种最基本的模式,是允许使用继承来扩展现有的类
继承示例
class Animal { move(distanceInMeters: number = 0) { console.log(`Animal moved ${distanceInMeters}m.`); } } class Dog extends Animal { bark() { console.log('Woof! Woof!'); } } const dog = new Dog(); dog.bark(); dog.move(10);
为 Dog 继承了 Animal 的功能,因此我们可以创建一个 Dog 的实例,它能够 bark() 和 move()
class Animal{ public name:string; // 温馨提示:子类继承父类,父类存在构造函数,子类必须实现构造函数 constructor(name:string){ this.name = name; } move(distanceInMeters:number){ console.log(`${this.name} moved ${distanceInMeters}m.`); } } class Dog extends Animal{ constructor(name:string){ super(name) } drak(){ console.log(this.name + " Woof! Woof!") } } class Snake extends Animal{ constructor(name:string){ super(name) } move(distanceInMeters: number): void { console.log(this.name + ":---" + distanceInMeters) // 执行父类的move方法 super.move(distanceInMeters) } } const d = new Dog("dog") d.move(100) d.drak() const s = new Snake("蛇") s.move(1000)
访问修饰符
在类中声明的属性与方法,可以添加访问修饰符控制可被访问的范围
TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public 、 private 和 protected
1、public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是public 的
2、private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
3、protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
默认为 public
我们可以自由的访问程序里定义的成员,在 TypeScript 里,成员都默认为 public
name 被设置为了 public ,所以直接访问实例的 name 属性是允许的
class Animal { public name: string; public constructor(theName: string) { this.name = theName } public move(distanceInMeters: number) { console.log(`${this.name} moved ${distanceInMeters}m.`); } }
理解 private
当成员被标记成 private 时,它就不能在声明它的类的外部访问
class Animal { private name: string; public constructor(theName: string) { this.name = theName } public move(distanceInMeters: number) { console.log(`${this.name} moved ${distanceInMeters}m.`); } } let a = new Animal("动物") console.log(a.name) // Property 'name' is private and only accessible within class 'Animal'.
理解 protected
protected 修饰符与 private 修饰符的行为很相似,但有一点不同,protected 成员在派生类(子类)中仍然可以访问
class Animal { protected name: string; public constructor(theName: string) { this.name = theName } } class Cat extends Animal{ constructor(theName:string){ super(theName) } public move(distanceInMeters: number) { console.log(`${this.name} moved ${distanceInMeters}m.`); } } let c = new Cat("猫") c.move(10)
readonly 修饰符
你可以使用 readonly 关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化
class Person { readonly name: string; constructor (theName: string) { this.name = theName; } } let p = new Person("iwen"); p.name = "Man with the 3-piece suit"; // 错误! name 是只读的.
与访问修饰符共用
注意如果 readonly 和其他访问修饰符同时存在的话,需要写在其后面
class Person { public readonly name: string; constructor (theName: string) { this.name = theName; } } let p = new Person("iwen"); p.name = "Man with the 3-piece suit"; // 错误! name 是只读的.
存取器
TypeScript 支持通过 getters/setters 来截取对对象成员的访问。它能帮助你有效的控制对对象成员的访问。
class Animal { fullName:string getFullName(){ console.log(this.fullName) } } let a = new Animal(); a.fullName = "itxiaotong" a.getFullName()
const fullNameMaxLength = 10; class Person { private _fullName: string; get fullName(): string { return this._fullName; } set fullName(newName: string) { if (newName && newName.length > fullNameMaxLength) { throw new Error("fullName has a max length of " + fullNameMaxLength); } this._fullName = newName; } } let p = new Person(); p.fullName = "itxiaotong"; if (p.fullName) { alert(p.fullName); }
温馨提示
这里会出现版本问题
1、TypeScript版本问题:增加 tsconfig.json ,并配置
2、编译时版本问题: tsc hello.ts -t es5
tsconfig.json
{ "compilerOptions": { "target": "es6" } }
实例方法与静态方法
实例方法我们很熟悉了,就是在类中定义的方法并且通过实例对象调用
使用 static 修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用
实例方法
class Person { public name:string; constructor(name:string){ this.name = name; } sayHello(){ console.log(`${this.name}:Hello`) } } const p = new Person("itxiaotong") p.sayHello()
静态方法
class Person { public name:string; constructor(name:string){ this.name = name; } sayHello(){ console.log(`${this.name}:Hello`) } static sayHi(){ console.log("Hi") } } Person.sayHi()
实例属性与静态属性
实例属性我们很熟悉,就是在类中直接定义的属性,可以通过实例对象调用
ES7 提案中,可以使用 static 定义一个静态属性,在TypeScript中也同样适用,通过类名调用
实例属性
class Person { public name:string; constructor(name:string){ this.name = name; } } const p = new Person("itxiaotong") p.sayHello()
静态属性
class Person { public name:string; static age = 20 constructor(name:string){ this.name = name; } } console.log(Person.age)
抽象类
什么是抽象类?
首先,抽象类是不允许被实例化的
其次,抽象类中的抽象方法必须被子类实现
abstract 用于定义抽象类和其中的抽象方法
abstract class Animal { public name:string; public constructor(name:string){ this.name = name; } abstract makeSound(): void; } class Cat extends Animal{ public constructor(name:string){ super(name) } makeSound(): void { console.log(this.name + "叫了") } } const c = new Cat("猫") c.makeSound()
接口初探
TypeScript 的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做 “鸭式辨型法” 或 “结构性子类型化”。 在 TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定
义契约
下面通过一个简单示例来观察接口是如何工作的
function printLabel(labeledObj: { label: string }) { console.log(labeledObj.label); } let myObj = { label: "Size 10 Object" } printLabel(myObj)
如果对象中是单一参数,那代码还具有可读性,可是如果参数是很多个,则大大降低了可读性
修改为接口处理参数形式
interface LabeledValue { label: string; } function printLabel(labeledObj: LabeledValue) { console.log(labeledObj.label); } let myObj = { label: "Size 10 Object" } printLabel(myObj);