如何写好JavaScript | 青训营笔记

81 阅读3分钟

前言

这是我参与「第四届青训营」笔记创作活动的的第3天

好JavaScript的原则

在知道如何写好JavaScript之前,我们会产生一个疑问,什么是好的JavaScript呢?我们应该用什么标准来衡量我们写的JavaScript代码好不好呢?

好JavaScript的原则可以分为以下三条:

  1. 各司其职
  2. 组件封装
  3. 过程抽象

各司其职

我们都知道前端三剑客是HTML,CSS,JavaScript。他们分别负责什么呢?HTML负责内容的呈现,CSS负责样式的呈现,JavaScript负责行为。让代码各司其职可以降低我们维护代码的成本,出bug的时候更快的找到责任的所在。

深夜食堂的例子

我们需要实现一个页面,这个页面可以切换白天模式和黑夜模式。我们可以如何实现呢?

image.png

第一段代码

          const btn = document.getElementById('modeBtn');
          btn.addEventListener('click', (e) => {
            const body = document.body;
            if(e.target.innerHTML === '🌞') {
              body.style.backgroundColor = 'black';
              body.style.color = 'white';
              e.target.innerHTML = '🌜';
            } else {
              body.style.backgroundColor = 'white';
              body.style.color = 'black';
              e.target.innerHTML = '🌞';
            }
          });

绑定按钮点击事件,根据事件赋予css的样式。

第二段代码

          const btn = document.getElementById('modeBtn');
          btn.addEventListener('click', (e) => {
            const body = document.body;
            if(body.className !== 'night') {
              body.className = 'night';
            } else {
              body.className = '';
            }
          });

事先写好两个样式class,绑定点击事件切换class。

第三段代码

          <input id="modeCheckBox" type="checkbox">
          <div class="content">
            <header>
              <label id="modeBtn" for="modeCheckBox"></label>
              <h1>深夜食堂</h1>
            </header>
            <main>
              <div class="pic">
                <img src="https://p2.ssl.qhimg.com/t0120cc20854dc91c1e.jpg">
              </div>
              <div class="description">
                <p>
                    这是一间营业时间从午夜十二点到早上七点的特殊食堂。这里的老板,不太爱说话,却总叫人吃得热泪盈眶……
                </p>
              </div>
            </main>
          </div>
          #modeCheckBox {
            display: none;
          }

          #modeCheckBox:checked + .content {
            background-color: black;
            color: white;
            transition: all 1s;
          }

不需要JavaScript来控制行为,而是用到了checkedbox的两种状态来转换页面的状态。

结论

  • HTML/CSS/JS 各司其责
  • 应当避免不必要的由 JS 直接操作样式
  • 可以用 class 来表示状态
  • 纯展示类交互寻求零 JS 方案

组件封装

在前端的主流框架中,我们很常见的一种思想就是组件化的思想。在组件化的思想下,我们编写组件,然后将组件应用于很多项目。在组件化的帮助下,如果我们的项目是得到一辆自行车,那么相当于我们就是拿着轮子的组件,车身的组件去拼装,而不是从制作一颗颗螺丝做起。组件化封装使得代码复用性高,提高了代码的价值。

组件的概念

组件是指Web页面上抽出来一个个包含模版(HTML)、功能(JS)和样式(CSS)的单元。好的组件具备封装性、正确性、扩展性、复用性。

组件的编写

  • 组件设计的原则:封装性、正确性、扩展性、复用性
  • 实现组件的步骤:结构设计、展现效果、行为设计
  • 三次重构
    1. 插件化
    2. 模板化
    3. 抽象化(组件框架)

过程抽象

  • 用来处理局部细节控制的一些方法
  • 函数式编程思想的基础应用

高阶函数

函数的结果return一个函数。

image.png

常用的高阶函数

once

function once(fn) {
  return function(...args) {
    if(fn) {
      const ret = fn.apply(this, args);
      fn = null;
      return ret;
    }
  }
}

throttle

function throttle(fn, time = 500){
  let timer;
  return function(...args){
    if(timer == null){
      fn.apply(this,  args);
      timer = setTimeout(() => {
        timer = null;
      }, time)
    }
  }
}

debounce

function debounce(fn, dur){
  dur = dur || 100;
  var timer;
  return function(){
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, dur);
  }
}

consumer

function consumer(fn, time){
  let tasks = [],
      timer;
  
  return function(...args){
    tasks.push(fn.bind(this, ...args));
    if(timer == null){
      timer = setInterval(() => {
        tasks.shift().call(this)
        if(tasks.length <= 0){
          clearInterval(timer);
          timer = null;
        }
      }, time)
    }
  }
}

iterative

function iterative(fn) {
  return function(subject, ...rest) {
    if(isIterable(subject)) {
      const ret = [];
      for(let obj of subject) {
        ret.push(fn.apply(this, [obj, ...rest]));
      }
      return ret;
    }
    return fn.apply(this, [subject, ...rest]);
  }
}