13面向对象之class下

一. 成员可见性

  • 有以下几种
    • public 类外可见
    • private 类内可见
ts 复制代码
class Person {
  private friend?: Person; //
  constructor(public name: string, friend?: Person) {
    this.friend = friend;
  }
  xxx() {
    this.friend; // 内部是可以用
  }
}

const p = new Person('Alice');
p.friend; //默认是public可见,如果前面加了private则没有这个属性,会报错
  • protected 子类可见
ts 复制代码
class Person {
  protected friend?: Person; //
  constructor(public name: string, friend?: Person) {
    this.friend = friend;
  }
}

const p = new Person('Alice');

class User extends Person {
  declare friend: User; // 重写一个属性的类型
  constructor(public id: number, name: string, friend?: User) {
    super(name, friend);
  }
  xxx() {
    this.friend; // 子类可以用,可以认为只有这个家族可以用
  }
}
  • 真私有属性,以上的private编译成js之后没有类型,依然可以调用,前面+#就是真正的私有属性,编译成js之后不会被擦除,因为这其实是js的语法
ts 复制代码
class Person {
  #friend?: Person; //
  constructor(public name: string, friend?: Person) {
    this.#friend = friend;
  }
}

二. static属性与static block

ts 复制代码
class Person {
  static xxx = 1;
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

Person.xxx; // 这就是Person上的属性,其实就是Person.xxx = 1,这个叫做类属性或者静态属性 
  • 需要注意static name会报错,同样也不能声明 prototype, length 等函数本身有的属性
ts 复制代码
class Person {
  static name = 1; // 会报错,因为js的类是靠函数模拟的,函数本身就有name的属性
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}
  • static可以用来表达类的共有属性,通过类属性来表达原型上共有属性的概念
ts 复制代码
class Person {
  static 种族 = '人类'; // 这个种族是所有对象共有的属性
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}
  • static block,假如有需求,需要在类里面获取某个计数
js 复制代码
class Foo {
  static #count = 0;
  static {
    // 意思是这段代码在类创建的时候使用,初始化私有属性
    const count = loadFromLocalStorage() || 0;
    Foo.#count += count;
  }
  constructor() {
    console.log(Foo.#count);
  }
}

三. 类加泛型

  • 例子一
ts 复制代码
class Hash<K, V> {
  map: Map<K, V> = new Map();
  set(key: K, value: V) {
    this.map.set(key, value);
  }
  get(key: K) {
    return this.map.get(key);
  }
}

const h = new Hash<string | number, string | number>();

h.set('name', 'hi');
h.get('name');

h.set([1, 2], 'hi'); // 会报错
  • 例子二,继承
ts 复制代码
class Hash<K, V> extends Map<K, V> {
  destroy() {
    this.clear();
  }
}

四. class表达式,其实就是匿名class

ts 复制代码
const Rectangle = class {
  constructor(public height: number, public width: number) {}
  area() {
    return this.height * this.width;
  }
};
const r = new Rectangle(100, 200);

五. 抽象类(不常用)

  • 为什么要有抽象类
    • interface只写类型,class又写类型又写实现,而抽象类就是为了实现一部分
ts 复制代码
abstract class C {
  // 也可以全部不实现,当成interface
  abstract name: string;
  age: number;
  constructor(age: number) {
    this.age = age;
  }
  abstract a(): number;
  abstract b(): number;
}

class D extends C {
  name: string;
  constructor(name: string) {
    super(18);
    this.name = name;
  }
  a() {
    return 1;
  }
  b() {
    return 2;
  }
}

const c = new D('Frank')

六. 把类当作参数

ts 复制代码
class Person {
  constructor(public name: string) {}
}

// 方式一
function f(X: typeof Person) {
  const p = new X('frank');
  console.log(p.name);
}

f(Person);

function ff(x: string) {
  console.log(x);
}
ff('hello'); // 我们可以发现,函数上的类型要比传入的类型范围大

// 方式二
function f2(X: new (name: string) => Person) {
  const p = new X('frank');
  console.log(p.name);
}

// f2(Person)的本质 (name: string) => obj

function ff2(x: (name: string) => string) {
  // ff2 类比f2
  x('frank');
}
ff2((name) => 'hello'); // 下面的返回值实际上比上面的高一点

第二种方式比较难理解,function f2(X: new (name: string) => Person)这是函数 f2 的定义。它接受一个参数 X,其中 X 的类型是一个构造函数,该构造函数接受一个名为 name 的字符串参数,并且该构造函数的返回类型必须是 Person

const p = new X('frank')在函数内部,它使用构造函数 X 创建了一个新的对象 p,并传递了 frank 作为参数。这段代码的关键点在于它使用了 TypeScript 中的函数类型签名来限定参数 X 的类型,确保 X 是一个能够创建 Person 对象的构造函数。

相关推荐
神仙别闹11 小时前
基于C语言实现B树存储的图书管理系统
c语言·前端·b树
玄魂11 小时前
如何查看、生成 github 开源项目star 图表
前端·开源·echarts
前端一小卒12 小时前
一个看似“送分”的需求为何翻车?——前端状态机实战指南
前端·javascript·面试
syt_101312 小时前
Object.defineProperty和Proxy实现拦截的区别
开发语言·前端·javascript
遝靑12 小时前
Flutter 跨端开发进阶:可复用自定义组件封装与多端适配实战(移动端 + Web + 桌面端)
前端·flutter
cypking12 小时前
Web前端移动端开发常见问题及解决方案(完整版)
前端
老前端的功夫12 小时前
Vue 3 vs Vue 2 深度解析:从架构革新到开发体验全面升级
前端·vue.js·架构
栀秋66612 小时前
深入浅出链表操作:从Dummy节点到快慢指针的实战精要
前端·javascript·算法
狗哥哥13 小时前
Vue 3 动态菜单渲染优化实战:从白屏到“零延迟”体验
前端·vue.js
青青很轻_13 小时前
Vue自定义拖拽指令架构解析:从零到一实现元素自由拖拽
前端·javascript·vue.js