• 被迫开始学习Typescript —— class


    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

    • 分析

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

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

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

    完整项目代码

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

  • 相关阅读:
    坚持用C++刷牛客题(剑指offer专题)
    ubuntu18下安装coova-chilli
    创建型设计模式之原型模式
    AlienSwap 锋芒初现,NFT 市场或将三分天下
    4.10扁平化嵌套序列
    JS之同步异步promise、async、await
    阿里云大数据助理工程师认证考试考什么内容?
    竞赛 基于大数据的时间序列股价预测分析与可视化 - lstm
    第三章 内存管理 十二、请求分页管理方式
    开源版商城源码V2.0【小程序 + H5+ 公众号 + APP】
  • 原文地址:https://www.cnblogs.com/jyk/p/16275700.html