JavaScript编码原则 | 青训营笔记

61 阅读3分钟

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

课程重点

  1. JavaScript 好代码的标准
  2. HTML/CSS/JS 各司其责
  3. 组件的定义解析及特征
  4. 组件封装基本方法
  5. 利用原生 JS 实现电商网站轮播图
  6. 过程抽象概念
  7. 高阶函数使用模式
  8. JavaScript 编程范式

写好JS的一些原则

  • 各司其职----让HTML、CSS和JavaScript职能分离
  • 组件封装----好的UI组件具备正确性、扩散性、复用性
  • 过程抽象----应用函数式编程思想

各司其责

image-20230116185542532

各司其责-例子

写一段JS,控制一个网页,让它支持浅色和深色两种浏览模式。 如果是你来实现,你会怎么做?

image-20230116185804177

深夜食堂:版本一

深夜食堂:版本二

深夜食堂:版本三

深夜食堂:结论

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

组件封装-例子

用原生JS写一个电商网站的轮播图,应该怎么实现?

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

结构设计:HTML

轮播图是一个典型的列表结构,我们可以使用无序列表

    元素来实现。

    <div id="my-slider" class="slider-list">
      <ul>
        <li class="slider-list__item--selected">
          <img src="https://p5.ssl.qhimg.com/t0119c74624763dd070.png"/>
        </li>
        <li class="slider-list__item">
          <img src="https://p4.ssl.qhimg.com/t01adbe3351db853eb3.jpg"/>
        </li>
        <li class="slider-list__item">
          <img src="https://p2.ssl.qhimg.com/t01645cd5ba0c3b60cb.jpg"/>
        </li>
        <li class="slider-list__item">
          <img src="https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg"/>
        </li>
      </ul>
    </div>
    

    展示效果:CSS

    • 使用CSS绝对定位讲图片重叠在同一个位置
    • 轮播图切换的状态使用修饰符(modifier)
    • 轮播图的切换动画使用CSS transition
    #my-slider{
      position: relative;
      width: 790px;
    }
    
    .slider-list ul{
      list-style-type:none;
      position: relative;
      padding: 0;
      margin: 0;
    }
    
    .slider-list__item,
    .slider-list__item--selected{
      position: absolute;
      transition: opacity 1s;
      opacity: 0;
      text-align: center;
    }
    
    .slider-list__item--selected{
      transition: opacity 1s;
      opacity: 1;
    }
    

    行为设计:API

    • API设计应保证原子操作,职责单一,满足灵活性。

    • Slider

      • +getSelectedItem()
      • +getSelectedItemIndex()
      • +slideTo()
      • +slideNext()
      • +slidePrevious()
    class Slider{
      constructor(id){
        this.container = document.getElementById(id);
        this.items = this.container
        .querySelectorAll('.slider-list__item, .slider-list__item--selected');
      }
      getSelectedItem(){
        const selected = this.container
          .querySelector('.slider-list__item--selected');
        return selected
      }
      getSelectedItemIndex(){
        return Array.from(this.items).indexOf(this.getSelectedItem());
      }
      slideTo(idx){
        const selected = this.getSelectedItem();
        if(selected){ 
          selected.className = 'slider-list__item';
        }
        const item = this.items[idx];
        if(item){
          item.className = 'slider-list__item--selected';
        }
      }
      slideNext(){
        const currentIdx = this.getSelectedItemIndex();
        const nextIdx = (currentIdx + 1) % this.items.length;
        this.slideTo(nextIdx);
      }
      slidePrevious(){
        const currentIdx = this.getSelectedItemIndex();
        const previousIdx = (this.items.length + currentIdx - 1)
          % this.items.length;
        this.slideTo(previousIdx);  
      }
    }
    

    行为设计:控制流

    • 使用自定义事件来解耦
      <a class="slide-list__next"></a>
      <a class="slide-list__previous"></a>
      <div class="slide-list__control">
        <span class="slide-list__control-buttons--selected"></span>
        <span class="slide-list__control-buttons"></span>
        <span class="slide-list__control-buttons"></span>
        <span class="slide-list__control-buttons"></span>
      </div>
    
    const detail = {index: idx}
    const event = new CusstommEvent('slide',{bubbles:true,detail})
    this.container.dispatchEvent(event)
    

    组件封装

    总结:基本方法

    • 结构设计
    • 展现效果
    • 行为设计
      • API(功能)
      • Event(控制流)

    重构:插件化

    解耦

    • 讲控制元素抽取成插件
    • 插件与组件之间通过依赖注入方式建立联系

    重构:模板化

    解耦

    • 将HTML模板化,更易于扩展

    image-20230116194149143

    重构:组件框架

    抽象

    • 将通用的组件模型抽象出来

    image-20230116194206016

    总结

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

    过程抽象

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

    过程抽象-例子

    操作次数限制

    • 一些一步交互
    • 一次性的HTTP请求

    Once

    • 为了能够让“只执行一次”的需求覆盖不同的事件处理,我们可以将这个需求剥离出来,这个过程我们称为过程抽象

    高阶函数

    • 以函数作为参数
    • 以函数作为返回值
    • 常用于作为函数装饰器

    image-20230116210256515

    常用高阶函数

    命令式与声明式

    image-20230116211912290

    例子

    总结

    • 过程抽象/HOF/装饰器
    • 命令式/声明式