跟着月影学JavaScript | 青训营笔记

156 阅读4分钟

跟着月影学JavaScript | 青训营笔记

这是我参与 \lceil第四届青训营\rfloor 笔记创作活动的第5天

课程的重点内容

1. 写好JavaScript的一些原则
2.各司其责
3. 组件封装
4. 过程抽象
5. 总结

一、写好JavaScript的一些原则

  • 各司其责
  • 组件封装
  • 过程抽象

image.png

二、各司其责(HTML、CSS、JS)

看示例,如果不各司其责,观察下面臃肿的代码

需求(写一段JS,实现浅色、深色切换的功能) 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 = '🌞';
    }
  });

优化后(没有直接操作样式,只操作行为)

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

下图给出了逐步优化的逻辑:但是,往往我们要考虑开发成本和难度,是否值得优化至最理想的状态,开发时要结合实际需求情况 image.png

三、组件封装

以电商网站轮播图需求为例

  • 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;
  }
  • JS (定义行为)
    • 行为API
    • 行为控制流

API

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);  
    }
  }

  const slider = new Slider('my-slider');
  slider.slideTo(3);

image.png

控制流

 <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 CustomEvent('slide', {bubbles:true, detail})
  this.container.dispatchEvent(event)
  • 进一步优化:重构(将组件抽象化,抽象出通用组件)
    • 插件化

      • 将控制元素抽取成插件
      • 插件与组件之间通过依赖注入方式建立联系
    • 模板化 (将HTML模板化,更易于扩展)

image.png

  • 抽象化 (将组件通用模型抽象出来)

image.png

image.png

四、过程抽象

  • 纯函数(函数返回结果只跟参数有关,不受外部环境的变化影响;同时函数的执行过程也产生副作用(副作用:函数执行的过程中对外部产生了可观察的变化))

  • react hooks是典型的过程抽象案例

  • 高阶函数(以函数为参数或以函数为返回值,当然参数和返回值也可以都是函数)

    • Once高阶函数:控制内部抽象只执行一次

      function once(fn) {
         return function(...args) {
           if(fn) {
             const ret = fn.apply(this, args);
             fn = null;
             return ret;
           }
         }
       }
      
    • HOF函数装饰器:以函数为参数,以函数为返回值

       function HOF0(fn) {
          return function(...args) {
            return fn.apply(this, args);
          }
        }
      

image.png

  • 其他常用高阶函数:
    • Throttle:防抖作呕用,例如:内容不变化到指定时间,出发某种行为
    • Consumer
    • Iterative
  • 为什么使用高阶函数 纯函数越多,可维护性越高 使用高阶函数能大大减少我们使用非纯函数的可能性

五、编程范式

命令式与声明式

image.png 例子

命令式

  let list = [1, 2, 3, 4];
  let mapl = [];
  for(let i = 0; i < list.length; i++) {
    mapl.push(list[i] * 2);
  }//重在表达怎样做的逻辑    How

声明式

 let list = [1, 2, 3, 4];
  const double = x => x * 2;
  list.map(double);//重在表达代码在做什么的逻辑  What

代码主要表义waht、how与命令式(Imperative)、声明式(Declarative)逻辑关系图

image.png

五、总结

大神系统讲了如何写好JavaScript代码的整体逻辑思路,具体的应用和细节需要不断去实践才能体会和理解。如果第一次感受有不理解的不必要死磕,当在做项目应用到技术的时候,再回头来研究,那样会使得自己更高效的掌握内容。

互联网知识太多,不可能只在理论层面就能学的通透,所以静心,万不可急于一时。珍惜每一次理论知识学习的机会,在后续实践中基于此再提升为自己的能力。积跬步至千里

知识很多,时间有限。了解了本质才能更容易找到学习的方向。

下篇笔记:前端设计模式应用

基础不牢,地动山摇

TO BE CONTINUED