知识导向
- 基础
- 修饰符
- readonly修饰符
- 参数属性
- 静态属性
- 可选属性
- 存取器
- 抽象类
- 实例类型
- 前面章节有关于类的补充
基础
定义类使用class
关键字
class Point {
public x: number
public y: number
constructor(x: number, y: number){
this.x = x
this.y = y
}
public getPosition(){
return `(${this.x},${this.y})`
}
}
const point = new Point(1,2)
console.log(point);
// 结果 Point { x: 1, y: 2 }
这里我们定义了一个叫Point的类,这个类里面包含了x,y
两个属性,一个构造函数(constructor
方法就构造函数)和一个getPosition
方法 。
我们在引用任何一个类成员的时候都用了this
。 它表示我们访问的是类的成员。
最后一行,我们使用new
构造了Point
类的一个实例。 它会调用之前定义的构造函数,创建一个ponint
类型的新对象,并执行构造函数初始化它。
继承
在TypeScript里,我们可以使用常用的面向对象模式。 基于类的程序设计中一种最基本的模式是允许使用继承来扩展现有的类。
// 父类/基类
class Parent {
public name: string
constructor(name: string) {
this.name = name
console.log(this.name);
}
}
// 子类/派生类
class Child extends Parent {
constructor(name: string) {
super(name)
}
}
const child = new Child('cyang')
//结果 cyang
这个例子展示了最基本的继承:类从基类中继承了属性和方法。这里,Child
是一个派生类,它派生自Parent
基类,通过extends
关键字。 派生类通常被称作子类,基类通常被称作超类或父类。
派生类包含了一个构造函数,它必须调用super()
,它会执行基类的构造函数。 而且,在构造函数里访问this
的属性之前,我们一定要调用super()
。 这个是TypeScript强制执行的一条重要规则。
修饰符
公共public
,私有private
,受保护的修饰符protected
公共的 public
(都可访问)
公共的,你可以将成员明确的标记为puclic
私有的private
(只能在类中访问)
当成员被标记成private
时,它就不能在声明它的类的外部访问。
class Parent {
private age: number
constructor(age: number) {
this.age = age
}
}
const p = new Parent(18)
console.log(p.age);//error 属性“age”为私有属性,只能在类“Parent”中访问。
这里的age是一个私有的属性,只能在类里面读取访问。
同样,在派生类中也一样不能访问。
class Child extends Parent {
constructor(age: number) {
super(age)
console.log(super.age);//error 通过 "super" 关键字只能访问基类的公共方法和受保护方法。
console.log(this.age);//error 属性“age”为私有属性,只能在类“Parent”中访问。
}
}
受保护的protected
(在类和子类中访问)
protected
修饰符与private
修饰符的行为很相似,但有一点不同,protected
成员在派生类中仍然可以访问。
例如:
class Parent {
protected age: number
constructor(age: number) {
this.age = age
}
protected getAge() {
return this.age
}
}
class Child extends Parent {
constructor(age: number) {
super(age)
console.log(super.age);//error 通过 "super" 关键字只能访问基类的公共方法和受保护方法。
console.log(super.getAge());
//结果 18
}
public getParent() {
return `${this.age}`
}
}
const child = new Child(18)
console.log(child.getParent());
//结果 18
注意,我们不能在Parent
类外使用age
,但是我们仍然可以通过Child
类的实例方法访问,因为Child
是由Parent
派生而来的。
构造函数也可以被标记成protected
。这意味着这个类不能在包含它的类外被实例化,但是能被继承。比如,
class Parent {
private age: number
protected constructor(age: number) {
this.age = age
}
}
class Child extends Parent {
constructor(age: number) {
super(age)
}
}
const p = new Parent(18)//error 类“Parent”的构造函数是受保护的,仅可在类声明中访问。
const c = new Child(18)
readonly
修饰符(只读)
你可以使用readonly
关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。
class UserInfo {
public readonly name: string
constructor(name: string){
this.name = name
}
}
const userinfo = new UserInfo('cyang')
userinfo.name = 'yangc'//error Cannot assign to 'name' because it is a read-only property.意思是这个属性是只读的,不可修改
参数属性
参数属性通过给构造函数参数前面添加一个访问限定符来声明。 使用public
限定一个参数属性会声明并初始化一个私有成员;对于private
,protected
和readonly
来说也是一样。
class Params {
constructor(public name: string) {}
}
const params = new Params('cyang')
console.log(params.name);
静态属性
我们也可以创建类的静态成员,这些属性存在于类本身上面而不是类的实例上。
class Parent {
public static age: number = 18
constructor() {}
public static getAge() {
return Parent.age
}
}
const p = new Parent()
console.log(p.age);//error Property 'age' is a static member of type 'Parent'.意思是这个成员是静态的,只能通过Parent类访问
console.log(Parent.age);
//结果 18
可选属性?
有些属性可传可不传,这时候,我们可以使用可选属性来定义它。
class Info {
public name: string
public age?: number
constructor(name: string, age?: number, public sex?: string) {
this.name = name
this.age = age
}
}
const info1 = new Info('cyang')
console.log(info1);
//结果 Info {sex: undefined, name: "cyang", age: undefined}
const info2 = new Info('cyang', 18)
console.log(info2);
//结果 Info {sex: undefined, name: "cyang", age: 18}
const info3 = new Info('cyang', 18, '男')
console.log(info3);
//结果 Info {sex: "男", name: "cyang", age: 18}
这里我们定义了属性、可选属性和可选参数属性。
存取器
TypeScript支持通过getters/setters来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问
get
: 在获取值时调用的方法
set
:在设置值时调用的方法
class Parent {
public name: string
public age?: number
private _GET: String
constructor(name: string, age?: number) {
this.name = name
this.age = age
this._GET = `这是需要取的值, ${this.name} ${this.age? `,${this.age}`: ''}`//可选参数的判断
}
get getTter() {
return this._GET
}
set setTter(value: string) {
console.log(value);
this._GET = value
}
}
const p = new Parent('cyang',18)
console.log(p.getTter);
//取值结果 这是需要取的值, cyang
console.log(p.name = 'yangc');
// 赋值结果 yangc
对于存取器有下面几点需要注意的:
首先,存取器要求你将编译器设置为输出ECMAScript 5或更高。 不支持降级到ECMAScript 3。 其次,只带有 get
不带有 set
的存取器自动被推断为 readonly
。 这在从代码生成 .d.ts
文件时是有帮助的,因为利用这个属性的用户会看到不允许够改变它的值。
抽象类
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。abstract
关键字是用于定义抽象类和在抽象类内部定义抽象方法。
abstract class People {
constructor(public name: string) {}
public abstract printName(): void
}
const p = new People()//error 无法创建抽象类的实例。
抽象类不能被实例化。
抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。 然而,抽象方法必须包含abstract
关键字并且可以包含访问修饰符。
abstract class People {
constructor(public name: string) {}
public abstract printName(): void
}
// const p = new People()//error 无法创建抽象类的实例。
class Man extends People {
constructor(name: string) {
super(name)
this.name = name
}
printName() {
console.log(this.name);
}
}
const m = new Man('cyang')
m.printName()
//打印出 cyang
实例类型
当你在TypeScript里声明了一个类的时候,实际上同时声明了很多东西。 首先就是类的实例的类型。
class Greeter {
public greeting: string
constructor(message: string) {
this.greeting = message;
}
public greet() {
return "Hello, " + this.greeting;
}
}
let greeter: Greeter = new Greeter("world");
console.log(greeter.greet());
//结果 Hello,world
这里,我们写了let greeter: Greeter
,意思是Greeter
类的实例的类型是Greeter
。
我们也创建了一个叫做构造函数的值。 这个函数会在我们使用new
创建类实例的时候被调用。
前面章节有关于类的补充
我们也可以把类当作接口使用:
class Point {
x: number;
y: number;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
泛型在类中的使用:
const create = <T>(c: new() => T): T => {
console.log(c);
//结果 Infos() {
// this.age = 18;
// }
return new c()
}
class Infos {
public age: number
constructor() {
this.age = 18
}
}
console.log(create<Infos>(Infos));
//结果 Parent{ age: 18 }
console.log(create<Infos>(Infos).age);
//结果 18
这里使用Infos
类作为泛型变量、参数的返回值类型和方法的返回值类型,new() => T
这个方法作为参数的类型,这里的create
是一个方法。
比较绕需多加动手操作,打印出不同的参数理解。