目录
Class的基础
Class 的定义
重载
成员函数的重载
Getter/Setter
索引器
组合和继承
类的继承
推荐使用组合或者泛型
成员
类的成员可见域
静态成员【static】
类型的相等
类型守卫【ts做窄化】
抽象类
TS的类型一致(所谓的子类可以赋值给父类)
小结
Class的基础
Class 的定义
class Point {
// ts得先声明一下
x: number
y:number
constructor(x: number, y: number) {
this.x = x
this.y = y
}
public add(p: Point) : Point {
return new Point(p.x + this.x, p.y + this.y)
}
}
const p = new Point(0, 0)
const newP = p.add(new Point(1, 1))
console.log(newP)
重载
成员函数的重载
class Point4 {
// ts得先声明一下
x: number
y: number
constructor(x: number, y: number) {
this.x = x
this.y = y
}
// class中对成员函数进行重载
public add(x: number, y: number): Point;
public add(p: Point): Point;
public add(x: number | Point, y?: number) {
if (typeof x === 'number') {
// 因为y是可选项,所有y: number | undefined;写作有!,
// 让null和undefined可以赋值给其他类型并通过编译
return new Point4(this.x + x, this.y + y!)
}
const p = x
return new Point4(this.x + p.x, this.y + p.y)
}
}
const p4 = new Point4(0, 0)
const newP4 = p4.add(new Point4(1, 1))
console.log(newP4)
Getter/Setter
class C {
_length = 0;
// ES6语义
get length() {
return this._length;
}
set length(value) {
this._length = value;
}
}
class C {
_length = 0;
// 函数语义
getLength() {
return this._length;
}
setLength(value) {
this._length = value;
}
}
索引器
class Arr<T> {
[i: number]: T // 索引器+类型标注
}
const a = new Arr<number>() // 索引器这个能力可以当成一个数组用,但是不常见
a[10] = 100
console.log(a[10]) // 100
组合和继承
类的继承
class Animal {
move() {
console.log("Moving along!");
}
}
class Dog extends Animal{ // 继承,重度耦合;Dog.move
woof(times: number) {
for(let i = 0; i < times; i++) {
console.log("woof!");
}
}
}
推荐使用组合或者泛型
interface Movable { // 接口
move() : void;
}
class Dog implements Movable { // 组合
move() {
console.log("move dog")
}
}
class Movable<T extends Animal> { // 泛型
animal:T
move() {
console.log(`${animal.getName()} is moving`)
}
}
成员
类的成员可见域
- public公开属性
- protected保护属性
- private私有属性
class Point {
public x: number // public
}
// x可以被任意程序访问
class Point {
private x : number
constructor() {
this.x = x // 成立,x是私有的,只有自己的类里面可以用
}
getX() {
return this.x
}
}
const p = new Point()
console.log(p.x) // Error x是私有属性,只有在Point类里面可以用
console.log(p.getX()) // ok
class Animal {
private _name1;
protected _name2;
}
class Dog extends Animal {
getName1(){
return this._name1 // Error 继承类也不能访问私有属性
}
getName2(){
return this._name2 // pass 继承类可以访问保护属性
}
}
静态成员【static】
class MyClass {
static x = 0; //静态成员
static printX() {
console.log(MyClass.x);
}
static name = "S!"// Error name是静态成员的保留字,所以用不了
}
console.log(MyClass.x);
MyClass.printX();
类型的相等
类型守卫【ts做窄化】
class FileSystemObject { // 文件系统的对象
isFile(): this is FileRep { // 守卫:文件类型断言,触发类型窄化
return this instanceof FileRep;
}
isDirectory(): this is Directory {// 守卫:目录类型断言,触发类型窄化
return this instanceof Directory;
}
isNetworked(): this is Networked & this {// 守卫:域名类型断言,触发类型窄化
return this.networked;
}
constructor(public path: string, private networked: boolean) {}
}
class FileRep extends FileSystemObject {
constructor(path: string, public content: string) {
//super()相当于FileRep.prototype.constructor.call(this)
super(path, false)
}
}
class Directory extends FileSystemObject {
children: FileSystemObject[];
}
const fso: FileSystemObject = new FileRep("foo/bar.txt", "foo");
is(fso.isFile()) { // 文件
fso.content;
// const fso: FileRep
} else if (fso.isDirectory()) { // 目录
fso.children;
// const fsoL:Directory
} else if (fso.isNetworked()) { // 地址
fso.host;
// const fso:Networked & FileSysremObject
}
抽象类
如果抽象类中没有具体方法,全都是抽象方法,那就等价于interface接口
abstract class Base { // 抽象类 TS独有,JS中没有
// 抽象类不能实例化,只能继承
abstract getName(): string;
printName() {
console.log("Hello," + this.getName());
}
}
// 无法创建抽象类的实例
const b = new Base();
class Derived extends Base {
// 继承抽象类,要实现一下继承过来的抽象类中的抽象方法 abstract getName()
getName() {
return "world";
}
}
const d = new Derived();
d.printName();
TS的类型一致(所谓的子类可以赋值给父类)
class Point1 {
x = 0;
y = 0;
}
class Point2 {
x = 0;
y = 0;
}
// OK 对于typescript来说,相同的结构,就是同一类型,
// TS检查,发生在编译时,做静态类型检查,看的就是静态成员是否一致
const p : Point1 = new Point2();
class Person {
name: string;
age:number;
}
class Employee {
name: string;
age:number;
salary: number;
}
// OK TS是按成员来分辨是否是继承,像上面这种,TS认为是隐形的继承
// Employee比Person多一个成员,认为 class Employee extends Person {}
const p: Person = new Employee();
小结
- TS如何判断类型的一致?代价如何?基于实际的每一项成员是否一致判断的。代价可以承担,就是慢点,而且发生在编译时。真正运行时,是不会有ts代码的,也不会帮我们生成新的代码不占我们的性能
- 在Class的使用中,TS有实现JS没有的能力吗?没有,去掉ts部分依然可以运行,ts只有少量的是js没有的,如枚举