【青训营】写好JS——做好抽象

简介: 【青训营】写好JS——做好抽象

所谓"抽象化",就是指从具体问题中,提取出具有共性的模式,再使用通用的解决方法加以处理。


一个例子:交通灯切换


让你用原生JS实现一个交通灯切换的组件,怎么抽象?怎么提高扩展性和复用性?


image.png


新手入门


你可能会觉得红绿灯很简单,三个状态用setTimeout()嵌套一下就可以了:


const traffic = document.getElementById('traffic');
(function reset() {
  traffic.className = 's1';
  setTimeout(function () {
    traffic.className = 's2';
    setTimeout(function () {
      traffic.className = 's3';
      setTimeout(reset, 1000)
    }, 1000)
  }, 1000);
})();
复制代码

但是,这时候如果需要复用,再加两个灯怎么办?再嵌套两个状态?


(function reset() {
  traffic.className = 's1';
  setTimeout(function () {
    traffic.className = 's2';
    setTimeout(function () {
      traffic.className = 's3';
      setTimeout(function () {
        traffic.className = 's4';
        setTimeout(function () {
          traffic.className = 's5';
          setTimeout(reset, 1000)
        }, 1000)
      }, 1000)
    }, 1000)
  }, 1000);
})();
复制代码


这样显然不行,多个异步函数回调会造成“callback hell”,有同学可能会说那用setInterval()就可以了,但是如果每个灯的持续时间不同呢?


数据抽象


第二个版本我们对交通灯做一个数据的抽象封装:


const traffic = document.getElementById('traffic');
const stateList = [
  { state: 'wait', last: 1000 },
  { state: 'stop', last: 3000 },
  { state: 'pass', last: 3000 },
];
function start(traffic, stateList) {
  function applyState(stateIdx) {
    const { state, last } = stateList[stateIdx];
    traffic.className = state;
    setTimeout(() => {
      applyState((stateIdx + 1) % stateList.length);
    }, last)
  }
  applyState(0);
}
start(traffic, stateList);
复制代码


通过传参调用setTimeout()来创建新的状态和持续时间,这样我们就得到了一个通用的版本。如果需要新的状态就在stateList里添加即可:


const stateList = [
  { state: 'wait', last: 1000 },
  { state: 'stop', last: 3000 },
  { state: 'pass', last: 3000 },
  { state: 'new', last: 500}
];
复制代码


不过因为我们没有做模板的抽象,所以要手动地添加部分HTML和CSS代码。


过程抽象


第三个版本我们使用刚讲过的过程抽象将其抽象成一个轮询的函数,每次去执行异步函数就可以了:


const traffic = document.getElementById('traffic');
function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
function poll(...fnList) {
  let stateIndex = 0;
  return async function (...args) {
    let fn = fnList[stateIndex++ % fnList.length];
    return await fn.apply(this, args);
  }
}
async function setState(state, ms) {
  traffic.className = state;
  await wait(ms);
}
let trafficStatePoll = poll(
  setState.bind(null, 'wait', 1000),
  setState.bind(null, 'stop', 3000),
  setState.bind(null, 'pass', 3000)
);
(async function () {
  // noprotect
  while (1) {
    await trafficStatePoll();
  }
}());
复制代码


简化通用


过度的抽象是一种负担。


wait()是异步的,setState()是瞬间的,这样既简化了代码,也更符合人的直觉:


const traffic = document.getElementById('traffic');
function wait(time) {
  return new Promise(resolve => setTimeout(resolve, time));
}
function setState(state) {
  traffic.className = state;
}
async function start() {
  //noprotect
  while (1) {
    setState('wait');
    await wait(1000);
    setState('stop');
    await wait(3000);
    setState('pass');
    await wait(3000);
  }
}
start();
复制代码


除了第一个版本不太行,其他版本都有自己的优缺点。抽象程度高,复用性高,但理解成本相应的也会很高,在很多时候我们需要做一个平衡。


我们追求的代码状态是:它既是一个优雅的代码,又不违背我们的直觉和思维习惯。

像本例中,我们只要把切换状态和等待两个函数切开来看,就很容易写出最后这个两全其美的代码。

目录
相关文章
|
2月前
|
JavaScript 前端开发
如何用JS实现团队功能
如何用JS实现团队功能
27 0
|
2月前
|
JavaScript Java 测试技术
网络安全科普系统开发与设计+springboot+vue.js附带文章和源代码设计说明文档ppt
网络安全科普系统开发与设计+springboot+vue.js附带文章和源代码设计说明文档ppt
29 5
|
2月前
|
JavaScript Java 测试技术
基于ssm+vue.js的小学生课外知识学习网站附带文章和源代码设计说明文档ppt
基于ssm+vue.js的小学生课外知识学习网站附带文章和源代码设计说明文档ppt
37 6
|
2月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的毕业生就业管理系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的毕业生就业管理系统附带文章和源代码设计说明文档ppt
18 2
|
2月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的法律咨询系统的分析与设计附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的法律咨询系统的分析与设计附带文章和源代码设计说明文档ppt
19 1
|
2月前
|
JavaScript Java 测试技术
基于ssm+vue.js的公司人力资源管理系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js的公司人力资源管理系统附带文章和源代码设计说明文档ppt
11 1
|
2月前
|
JavaScript Java 测试技术
基于ssm+vue.js的金鱼销售平台附带文章和源代码设计说明文档ppt
基于ssm+vue.js的金鱼销售平台附带文章和源代码设计说明文档ppt
16 1
|
2月前
|
JavaScript Java 测试技术
基于ssm+vue.js的大学学生成长系附带文章和源代码设计说明文档ppt
基于ssm+vue.js的大学学生成长系附带文章和源代码设计说明文档ppt
14 1
|
2月前
|
JavaScript Java 测试技术
基于springboot+vue.js的企业员工薪酬关系附带文章和源代码设计说明文档ppt
基于springboot+vue.js的企业员工薪酬关系附带文章和源代码设计说明文档ppt
18 2
|
2月前
|
JavaScript Java 测试技术
基于小程序的外卖点餐+springboot+vue.js附带文章和源代码设计说明文档ppt
基于小程序的外卖点餐+springboot+vue.js附带文章和源代码设计说明文档ppt
23 2