美文网首页前端开发那些事儿vue、javascript
让你的 JS 代码变得更加优雅且可维护

让你的 JS 代码变得更加优雅且可维护

作者: 源大侠 | 来源:发表于2021-02-28 09:50 被阅读0次

在开发的过程中,总结了一些优化开发的编码经验,当然这些经验都是前人总结出来的,这次就特别拿出来跟大家一起分享,当然这些经验不一定是最佳实践.

拒绝魔法

众所周知,魔法是这样的


image.png

哦,不是。。
在编程的世界里也有魔法,一般称其为:魔法数字,魔法变量,魔法字符串。例如这样:

const a = await abcdefg();
console.log(a === 200);
const b = await asdfgh();
if (b === 0) {
} else if (b === 1) {
} else if (b === 2) {};
for (let i = 0; i < 10; i++) {};

以上直接出现的,莫名其妙的变量名,字符串以及判断条件数字,就叫魔法。。。
这种写法写出来的代码晦涩难懂,难以维护,隐藏 BUG 多,除非你准备给接手的人埋坑,或者准备辞职,不然千万别这么写(容易被打断腿,👨🦽 )
那么怎么写才更优雅?

语义化

首先便是语义化。一个是变量,常量的语义化,例如:

const SUCCESS_STATUS = 200;
const requestStatus = await getStatus();
console.log(requestStatus === SUCCESS_STATUS);
const userRole = await getUserRole();
const GUEST_CODE = 0;
const USER_CODE = 1;
const ADMIN_CODE = 2;
if (userRole === GUEST_CODE) {
} else if (userRole === USER_CODE) {
} else if (userRole === ADMIN_CODE) {};
const MAX_NUM = 10;
const MIN_NUM = 0;
for (let currentNum = MIN_NUM; currentNum < MAX_NUM; currentNum++) {};

一般的规则就是变量用小写,常量用大写,把变量名语义化,那么当你看到这段代码的时候,一眼就能知道它是做什么的,而不是非得要浪费时间看完上下文,或者是猜。

枚举

对于上面判断 userRole 的代码,其实我们可以用更优雅的方式去实现,那就是 枚举 。
按照维基百科的说明:在数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常(但不总是)重叠。
其实就是组织收集有关联变量的一种方式。枚举的好处在于方便多状态的管理,以及可读性更强。例如:

const ROLES = {
  GUEST: 0,
  USER: 1,
  ADMIN: 2
};
const userRole = await getUserRole();
if (userRole === ROLES.GUEST) {
} else if (userRole === ROLES.USER) {
} else if (userRole === ROLES.ADMIN) {};

通过枚举的方式归纳起来,维护起来更方便,而且要添加状态直接在 ROLES 对象里写就行,更方便快捷。

策略模式

维基百科上说:策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。
上面的代码依旧是可优化的,在这里我们可以利用策略模式来做进一层的优化。
具体的例子就是如下:

const ROLES = {
  GUEST: 0,
  USER: 1,
  ADMIN: 2
};
const ROLE_METHODS = {
  [ROLES.GUEST]() {},
  [ROLES.USER]() {},
  [ROLES.ADMIN]() {},
};
const userRole = await getUserRole();
ROLE_METHODS[userRole]();

通过上面的写法,我们可以知道,当我们需要增加角色,或者修改角色数字的时候,只需要修改 ROLES 里对应的字段,以及 ROLE_METHODS 里的方法即可,这样我们就可以将可能很冗长的 if...else 代码给抽离出来,颗粒度更细,更好维护。

更在状态

除了上面的方式之外,我们还可以利用“ 状态 ”的概念来写代码。在看代码之前,我们先了解下什么是 “有限状态机”。
根据维基百科的解释:有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机(英语:finite-state automation,缩写:FSA),简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型。
例如我们熟悉的 Promise ,它就是在状态集:PENDIN 、 FULFILLED 、 REJECTED 之间单向流转的有限状态机。
状态机的概念跟策略模式类似,实现方式也类似,这里面最大的不同是在于 “语义” 。
策略模式更适合于互不依赖,同时只能存在一个状态的场景,例如:

const 吃 = {
  沙县大酒店() {
    吃云吞()
  },
  开封菜() {
    吃汉堡()
  },
  在家() {
    吃外卖()
  }
};

这里面如果我们肚子饿了,就只能在 沙县大酒店() , 开封菜() , 在家() 这几个状态里选。
你不能都吃,当然以下情况除外。。。

image.png

如果是状态模式,则会有这种情况:

const 打工人 = {
  起床() {},
  上班() {},
  加班() {},
  下班() {}
};
// 早上6点
打工人.起床();
// 早上9点
打工人.上班();
// 晚上6点
打工人.加班();
// 晚上12点
打工人.下班();

这里的打工人根据不同的时间,进行不同的任务,便是打工人模式,哦不,状态模式。这里的时间就是状态。
我们举个实际的业务例子,就是订单列表页,通常我们的订单可能有这几种状态:


image.png

不同的状态展示的 UI 也不同,所以我们以不同的状态划分好模块之后,代码写起来就会清晰很多,我们以 Vue 代码为例:

// contants.js
export const ORDER_STATUS = {
  INIT: 0, // 初始化
  CREATED: 1, // 订单创建
  ARREARAGE: 2, // 待支付
  PURCHASED: 3, // 已购买
  SHIPPED: 4, // 已发货
  COMPLETED: 5 // 已完成
};
// order.vue
<template>
  <div>
        <section v-if="orderIsInit"></section>
        <section v-if="orderIsCreated"></section>
        <section v-if="orderIsArrearage"></section>
        <section v-if="orderIsPurchased"></section>
        <section v-if="orderIsShipped"></section>
        <section v-if="orderIsCompleted"></section>
  </div>
</template>

<script>
  import ORDER_STATUS from './contants';
  import eq from 'lodash';
  
  export default {
    computed: {
      /**
       * @func
       * @name orderIsInit
       * @desc 判断订单是否初始化的状态
       * @returns {string} 判断订单是否初始化的状态
       */
      orderIsInit() {
        return eq(this.orderStatus, ORDER_STATUS.INIT);
      },
      /**
       * @func
       * @name orderIsCreated
       * @desc 判断订单是否已创建的状态
       * @returns {string} 订单是否已创建
       */
      orderIsCreated() {
        return eq(this.orderStatus, ORDER_STATUS.CREATED);
      },
      /**
       * @func
       * @name orderIsArrearage
       * @desc 判断订单是否未付款的状态
       * @returns {string} 订单是否未付款
       */
      orderIsArrearage() {
        return eq(this.orderStatus, ORDER_STATUS.ARREARAGE);
      },
      /**
       * @func
       * @name orderIsPurchased
       * @desc 判断订单是否已购买的状态
       * @returns {string} 订单是否已购买
       */
      orderIsPurchased() {
        return eq(this.orderStatus, ORDER_STATUS.PURCHASED);
      },
      /**
       * @func
       * @name orderIsShipped
       * @desc 判断订单是否已发货的状态
       * @returns {string} 订单是否已发货
       */
      orderIsShipped() {
        return eq(this.orderStatus, ORDER_STATUS.SHIPPED);
      },
      /**
       * @func
       * @name orderIsCompleted
       * @desc 判断订单是否已完成的状态
       * @returns {string} 订单是否已完成
       */
      orderIsCompleted() {
        return eq(this.orderStatus, ORDER_STATUS.COMPLETED);
      },
    },
    data() {
      return {
        orderStatus: ORDER_STATUS.INIT // 订单状态
      }
    },
    methods: {
      /**
       * @func
       * @name getOrderStatus
       * @desc 判断订单状态
       * @returns {string} 返回当前订单状态
       */
      async getOrderStatus() {}
    },
    async created() {
      this.orderStatus = await this.getOrderStatus();
    }
  }
</script>

将页面组件按状态划分,实现独立自治,这样子既能防止代码耦合,方便维护 debug,也方便开发者自测,如果需要看不同状态的展示效果,只要手动给 orderStatus 赋值即可,方便快捷

面向切面

按照维基百科的解释:面向切面的程序设计(Aspect-oriented programming,AOP,又译作面向方面的程序设计、剖面导向程序设计)是计算机科学中的一种程序设计思想,旨在将横切关注点与业务主体进行进一步分离,以提高程序代码的模块化程度。

我们看回上面打工人的场景,假定老板想要知道打工人每个状态开始前跟结束前的时间以及做点什么,那么该怎么做呢?这个时候我们不难想到可以直接往状态函数里写代码,例如:

const 打工人 = {
  起床() {
    老板.start();
    打工人.do();
    老板.end();
  },
  上班() {
    老板.start();
    打工人.do();
    老板.end();
  },
  加班() {
    老板.start();
    打工人.do();
    老板.end();
  },
  下班() {
    老板.start();
    打工人.do();
    老板.end();
  }
};
// 早上6点
打工人.起床();
// 早上9点
打工人.上班();
// 晚上6点
打工人.加班();
// 晚上12点
打工人.下班();

但是这样打工人一下子就察觉到到了老板在监控他的生活,如果要做到不被人察觉(不影响业务逻辑),那我们既可以采用 AOP 的实现方式。代码如下:

import eq from 'lodash';
const TYPES = {
  FUNCTION: 'function'
}
const 老板监控中的打工人 = new Proxy(打工人, {
    get(target, key, value, receiver) {
        console.log('老板开始看你了~');
       const res = Reflect.get(target, key, value, receiver);
       const 打工人任务 = eq(typeof res, TYPES.FUNCTION) ? res() : res;
        console.log('老板开始记你小本本了~');
        return () => 打工人任务;
    }
});

所以我们可以看到以下结果:

image.png

这样子,我们就可以轻松简单地监控到了打工人每天干的活,而且还不让打工人发现,简直是资本家听了都流泪呀。

作者:陈大鱼头
github:KRISACHAN

相关文章

  • 让你的 JS 代码变得更加优雅且可维护

    在开发的过程中,总结了一些优化开发的编码经验,当然这些经验都是前人总结出来的,这次就特别拿出来跟大家一起分享,当然...

  • JS 如何书写优雅的代码

    优雅的代码:符合规范,代码合理、易于阅读和维护。 一、备注 1.文档注释: 简单描述当前js文件作用。是页面js逻...

  • App组件化

    优点 业务分层、解耦,使代码变得可维护;有效的拆分、组织日益庞大的工程代码,使工程目录变得可维护;便于各业务功能拆...

  • 编写可维护的js代码。

    private 和 public 可这样的区分。

  • 设计模式之状态模式

    开始总结设计模式主要是因为项目在实际的使用中,适合的设计模式能够使代码变得更加优雅,也更便于维护。各种设计模式的精...

  • 2018-05-10

    require.js的使用 require.js可以实现js文件的异步加载,使代码维护更加方便,并且也会使页面的渲...

  • 小猿圈python知识点分享之tablib模块的使用

    python中有很多模块,因为这些模块的封装,让代码更加优雅、功能更加强大,编程变得不那么复杂,小猿圈Python...

  • 2018-01-10

    你不知道的js上篇 关于this为什么要用this,显式传递上下文对象会让代码变得越来越混乱,使用this更优雅的...

  • 简单,解决很多问题

    依赖更少,更能自由和放松地生活。 当然,也会让生活变得更加细致于优雅。 你的决定将发自本能,你的穿着风格将更加优雅...

  • JavaScript 函数式编程:看完这篇就够了

    作为程序员,你可能希望编写优雅、可维护、可伸缩、可预测的代码。函数式编程(FP)的原则可以极大地帮助实现这些目标。...

网友评论

    本文标题:让你的 JS 代码变得更加优雅且可维护

    本文链接:https://www.haomeiwen.com/subject/rxtgfltx.html