关于重构问题——编写可维护性高的代码

一、使用TypeScript:

背景:

RollBar是一个网页检测的网站,该网站统计了2018年前端项目抛出异常的种类,其中有七种是type error,即类型错误。异常最多的类型是读取了undefined变量的属性

而这个问题可以通过TS定义严格的数据类型解决:

type TypeApple = { name: string, count: number }
/** @type {TypeApple} */
const apple = { name: 'foo', count: 100 }

TS和VSCode(一款IDE)结合,也可以实现静态类型检测,只不过使用注释形式,一样支持tsconfig.json和自定义Typing。

如何使用TS:

npm install –g typescript
tsc –v

1.新建 .ts 后缀的文件 —— 2.编写满足 ts 风格的代码——3.使用tsc编译ts文件(最后得到的还是js文件)

TS主要语法:

1.类型系统:

2.接口

 在TypeScript中,接口的作用是对值所拥有的结构进行类型检查,接口是一种结构约束。同时提供了一种方式去抽象代码。

3.类

js本身并不是一种OOP(面向对象编程)的语言,并没有类这样一个概念。JS的对象使用原型链进行继承和扩展。ES6中提供的Class关键字只是一个语法糖,让你用面向对象的方式编写类,底层还是原型链的链接。

继承,以某个类为父类,继承所有的属性和方法,同时可以进行扩展和重写方法:

a.protected 在类自身的内部可以访问,子类可以访问,外部无法访问;

b.private 仅可在类自身的内部进行访问,子类无法访问,外部无法访问。

抽象类。抽象类无法实例化,只能作为其他类的基类。不同于接口,抽象类可以描述类的实现细节。抽象方法在派生类中必须实现。

4.函数:

TS函数参数和返回值的类型指定以及函数重载。

指定了函数的参数类型和返回结果,函数的功能就比较特定了。但是js毕竟是动态类型的函数,js内根据参数类型不同返回不同的类型比较常见,所以ts提供函数重载功能

5.断言:

注意事项:

1.文件声明(开发环境对TS文件的支持):规定namespace+第三方库+管理工具+声明文件

2.项目工程化:

  a.使用webpack的文件变动检测机制,自定义启动脚本(当检测到文件发生变化时重新编译和运行入口js);

  b.使用ts-node和pm2,更改pm2的启动配置,让pm2使用ts-node直接运行ts的入口文件。

3.tsconfig.json相关:

  类似eslint,例如是否允许 使用 any 类型, 是否允许存在未使用的变量等等。

  https://www.tslang.cn/docs/handbook/compiler-options.html 

  https://www.tslang.cn/docs/handbook/error.html

二、细化模块分类:

一般情况下,模块都会有耦合。但如果耦合度过高,往往是因为模块没有细分到位。如果细化模块?举例,假如有一个模块叫Operation,里面既包含操作相关逻辑,也有操作面板逻辑。随着业务发展,操作面板逻辑越来越多。我们完全可以将操作面板逻辑单独抽成一个模块OperationPanel

化繁为简:

//1.If的使用简单粗暴,容易理解。

if ( animalType === 'dog' ) {
    console.log( 'Wang!' )
} else if ( animalType === 'cat' ) {
    console.log( 'Miao!' )
} else if ( animalType === 'bird' ) {
    console.log( 'Jiu!' )
}
//2.Switch可以看做是If的简化。

switch ( animalType ) {
    case 'dog':
      console.log( 'Wang!' )
      break
    case 'cat':
      console.log( 'Miao!' )
      break
    case 'bird':
      console.log( 'Jiu!' )
      break
}
//3.而Map针对性最强,并且最简洁、最易于维护。

const logMap = {
    dog: () => console.log( 'Wang!' ),
    cat: () => console.log( 'Miao!' ),
    bird: () => console.log( 'Jiu!' ),
}
logMap[ animalType ]()

 

三、解耦可视化库和Vue/Vuex:

class Counter {
  // # state  
  /** @type {number} */
  count = 0

  // # getters
  get countText() { return `Count is: ${ this.count }` }

  // # mutations
  /** @param {number} count*/
  SET_COUNT = count => { this.count = count }
  
  // # actions
  /** @param {number} count*/
  logCount = ( count ) => {
    this.SET_COUNT( count )
    console.log( this.countText )
  }
}

 

“使用getters和mutations”。比如定义一个模块的operationGetters.js, 里面提供各种用来获取与操作有关的常量和方法。

export const OPERATION_TYPE_A = 0
export const OPERATION_TYPE_B = 1

export const OPERATION_TITLE_MAP = {
  [ OPERATION_TYPE_A ]: 'Title A',
  [ OPERATION_TYPE_B ]: 'Title B',
}

export const getOperationTitleByType = type => OPERATION_TITLE_MAP[ type ]

定义mutations则是定义一个提供相关各种变更数据方法的文件。在维护代码的时候,查找变更方法名即可直接找到更改数据的出处。

export const SET_OPERATION_TITLE = ( operation, title ) => { operation.title = title }

-end-

posted @ 2019-08-01 10:45  桥南小院  阅读(287)  评论(0编辑  收藏  举报