0
点赞
收藏
分享

微信扫一扫

2-1-12 TS Class

萧萧雨潇潇 2022-05-03 阅读 69

定义类和成员

class Point {
    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 Point {
		// ...
    
    public add(x : number, y : number) : Point;
    public add(p : Point) : Point;
    public add(x : number | Point, y? : number) {
      if(typeof x === 'number') {
          return new Point(this.x + x ,  this.y + y!)
      }
      const p = x
      return new Point(this.x + p.x, this.y + p.y)
    }
  }

  const p = new Point(0, 0)
  const newP = p.add(new Point(1, 1))
  console.log(newP)

重载可以获得更好的书写提示体验。

Getter / Setter

获取和设置变成两个方法,隐藏了内部具体的实现。

class C {
  _length = 0;
  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

类型继承

interface BasicAddress {
  name?: string;
  street: string;
  city: string;
  country: string;
  postalCode: string;
}
 
interface AddressWithUnit extends BasicAddress {
  unit: string;
}

类的继承

class Animal {
  move() {
    console.log("Moving along!");
  }
}
 
class Dog extends Animal {
  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

`public` `private` `protected` 这3个和其他语言一样,具体的:

`public` 成员允许所有程序访问,如果不标识任何约束,那么默认就是`public`

class Point {
    x : number
}
// x可以被任意程序访问

`private` 成员只允许在当前类中访问。

class Point {
    private x : number
    constructor(){
        this.x = x // 成立
    }
    
    getX(){
        return this.x
    }
}

const p = new Point()
console.log(p.x)
// Error : Property 'x' is private and only accessible within class 'Point'.ts(2341)

`protected` 允许在当前类和它的继承类中访问成员。

class Animal {
    private _name1;
    protected _name2;
}

class Dog extends Animal{
    getName1(){
        return this._name1 // Error
    }
    
    getName2(){
        return this._name2 // pass
    }
}

静态成员

class MyClass {
  static x = 0;
  static printX() {
    console.log(MyClass.x);
  }
}
console.log(MyClass.x);
MyClass.printX();

静态成员和类的实例没有关系,静态成员、静态方法都绑定在类型本身上。

静态成员也会继承:

class Base {
  static getGreeting() {
    return "Hello world";
  }
}
class Derived extends Base {
  myGreeting = Derived.getGreeting();
}

保留的特殊静态成员名称:

class S {
  static name = "S!";
// Error : Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'S'.
}

为什么没有静态类?

在 Java中有静态类, 静态类是相对类的嵌套的概念,在JS虽然也存在类的嵌套,但是遵循闭包的逻辑,比如:

class A {
    x : number
    foo(){      
      const y = 0
      class B{
        bar(){
          this.x // Property 'x' does not exist on type 'B'
          console.log(y)
        }
      }
      return B
    }
  }

因为有B包的逻辑,就不太适合再增加,让嵌套类可以访问外部类成员的逻辑了。 逻辑太复杂,不利于程序员写程序。

类型守卫

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(path, false);
  }
}
 
class Directory extends FileSystemObject {
  children: FileSystemObject[];
}
 
interface Networked {
  host: string;
}
 
const fso: FileSystemObject = new FileRep("foo/bar.txt", "foo");
 
if (fso.isFile()) {
  fso.content;  
  //const fso: FileRep
} else if (fso.isDirectory()) {
  fso.children;
  //const fso: Directory
} else if (fso.isNetworked()) {
  fso.host;
  
  //const fso: Networked & FileSystemObject
}

抽象类

抽象类不可以实例化

abstract class Base {
  abstract getName(): string;
 
  printName() {
    console.log("Hello, " + this.getName());
  }
}
 
const b = new Base();
// Cannot create an instance of an abstract class.

必须继承:

class Derived extends Base {
  getName() {
    return "world";
  }
}
 
const d = new Derived();
d.printName();

类型的关系

TS会通过成员去思考类型是否一致:

class Point1 {
  x = 0;
  y = 0;
}
 
class Point2 {
  x = 0;
  y = 0;
}
 
// OK
const p: Point1 = new Point2();

另一个例子:

class Person {
  name: string;
  age: number;
}
 
class Employee {
  name: string;
  age: number;
  salary: number;
}
 
// OK
const p: Person = new Employee();

最后一个例子:

class Empty {}
 
function fn(x: Empty) {
  // can't do anything with 'x', so I won't
}
 
// All OK!
fn(window);
fn({});
fn(fn);

1

举报

相关推荐

0 条评论