前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >被迫开始学习Typescript —— class

被迫开始学习Typescript —— class

作者头像
用户1174620
发布2022-05-18 11:04:46
3670
发布2022-05-18 11:04:46
举报

TS 的 class 看起来和 ES6 的 Class 有点像,基本上差别不大,除了 可以继承(实现)接口、私有成员、只读等之外。

参考:https://typescript.bootcss.com/classes.html

基本用法

我们可以定义一个 class,设置几个属性,然后设置一个方法,封装 Object.assign 简化reactive 的赋值操作。

  • 创建自己的对象基类
  import type { InjectionKey } from 'vue'

  class BaseObject {
    $id: string | symbol | InjectionKey<string>
    name: string
    age: number

    constructor (id: string, name: string, age: number) {
      this.$id = id
      this.name = name
      this.age = age
    }
    
    set $state(value: any) {
      Object.assign(this, value)
    }
  }
  • 使用
  import { reactive, defineComponent } from 'vue'

  const _state = new BaseObject('007', 'jyk')
  const state = reactive(_state)

  state.$state = {
    name: '直接赋值'
  }

看着是不是眼熟?你猜对了!这里参考 Pinia 设置 $state ,实现给 reactive 直接赋值的功能。

reactive 哪都好,只是整体赋值的时候有点郁闷,这里简单封装了一下,实现直接赋值的功能。

类的继承

上面的方法只是封装了对象,那么数组怎么办呢?这里就需要用到“继承” extends 的用法。

  • 继承 js 的 Array 创建自己的数组类
  class BaseArray extends Array  {
    $id: string | symbol | InjectionKey<string>
   
    constructor () {
      // 调用父类的 constructor()
      super()
      this.$id = 'array'
    }

    set $state(value: any) {
      this.length = 0
      if (Array.isArray(value)) {
        this.push(...value)
      } else {
        this.push(value)
      }
    }
  }
  • 使用
const _state2 = new BaseArray()
const state2 = reactive(_state2)

state2.$state = [
  {
    name: '008'
  },
  {
    name: '009'
  }
]

这样数组形式的 reactive ,也可以直接赋值了,是不是方便很多?

继承的是原生数组,所以拥有了数组的所有功能。 另外,子类的constructor里面,需要调用 super() 才会有 this。

实现接口

观察上面的两个 class,会发现拥有相同的成员:id 和 state。那么要不要约束一下?

如果想要实现约束功能的话,可以定义一个 interface 来实现。

  • 定义接口
  interface IState {
    $id: string | symbol | InjectionKey<string>
    set $state(value: any)
  }
  • 实现接口
  class BaseObject implements IState {
    略
  }

  class BaseArray extends Array implements IState {
    略
  }

这样设置之后,类的成员就要复合接口的定义,不符合的话会出现提示。

私有成员、只读成员

虽然可以使用 private、readonly 标识私有成员和只读成员,只是嘛,到目前为止有点鸡肋。因为只是在 TS 的范畴内给出错误提示,但是完全不影响运行。

那么能不能变相实现一下呢?可以的,只是有点绕圈圈,另外似乎不太正规。

我们把 $id 改为只读、伪隐藏成员。

  • 修改一下接口,使用访问器(get)设置 $id
  interface IState {
    get $id(): string | symbol | InjectionKey<string>
    set $state(value: any)
  }
  • 修改一下对象基类,使用 get 访问器
  class BaseObject implements IState {
    get $id(): string | symbol | InjectionKey<string>
    略
  }
  • 创建对象实例的函数
  function createState(id: string, name: string, age: number) {
    // 继承 BaseObject 再定义一个class
    class myState extends BaseObject {
      constructor (name: string, age: number) {
        // 调用父类的 constructor()
        super(name, age)
      }
      // 使用 override 覆盖父类 $id
      override get $id() {
        return id
      }
    }
    
    const _state = new myState(name, age)
    const state = reactive(_state)

    return state
  }
  • 使用
  const state3 = createState('010', 'jyk0013', 29)
  console.log(state3)
  console.log('state3 - keys', Object.keys(state3))
  for (const key in state3) {
    console.log(key, state3[key])
  }
  • 效果
简单的state.png
简单的state.png
  • 分析

把 $id 改为 get 访问器的方式,可以实现 readonly 的效果。

$id 放在 class (myState) 的“原型”上面,可以避免被遍历出来,这样就实现了伪隐藏的效果。

当然 使用 state.$id 的方式还是可以访问到的,所以是伪隐藏。

完整项目代码

https://gitee.com/naturefw-code/nf-rollup-state

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-05-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本用法
  • 类的继承
  • 实现接口
  • 私有成员、只读成员
  • 完整项目代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档