浅说JS|青训营笔记

165 阅读4分钟

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

一、什么是JS

js是JavaScript的简称,是一种直译式脚本语言,它是web前端中不可缺少的一部分,它用于增强HTML页面,通常可以嵌入HTML代码中,JavaScript以交互式和动态的方式呈现网页,这允许页面对事件做出反应,展示特殊效果。

JS是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言。它经常和web前端放在一起,那么web前端js是什么呢?

web前端js

Javascript(JS)主要用于 Web。它用于增强 HTML 页面,通常可以嵌入 HTML 代码中。JavaScript 以交互式和动态的方式呈现网页。这允许页面对事件做出反应,展示特殊效果,接受可变文本,验证数据,创建 cookie,检测用户的浏览器等。

二、写好JS的原则

  • 各司其职

    让HTML、CSS和JavaScript职能分离。

  • 组件封装

    好的UI组件具备正确性、扩展性、复用性。

  • 过程抽象

    应用函数式编程思想

各司其职原则

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

代表一:入门级选手

分析:该版本通过JS代码改变颜色,难以让其他人读懂代码。

代表二:进阶选手

分析:通过修改body元素的class属性改变颜色,较好。

代表三:终极选手

分析:样式效果完全由CSS实现,实现了各司其职原则,该代码更好。

结论

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

组件封装原则

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

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

分析1:结构HTML

轮播图是一个典型的列表结构,我们可以使用无序列表ul元素来实现。

 <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>

分析2:表现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;
  }

分析3:行为JS

  1. API:Slider

    • +getSelectedItem()
    • +getSelectedItemIndex()
    • +slideTo()
    • +slideNext()
    • +slidePrevious()
  2. 控制流:

    • 使用自定义事件来解耦。
  3. 重构:插件化

    解耦

    • 将控制元素抽取成插件
    • 插件与组件之间通过依赖注入方式建立联系
  4. 重构:模板化

    解耦

    • 将HTML模板化,更易于扩展
  5. 组件框架

    抽象

    • 将组件通用模型抽象出来
 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);

结论

  • 组件设计的原则:封装性、正确性、扩展性、复用性

  • 实现组件的步骤:结构设计、展现效果、行为设计

  • 三次重构

    1. 插件化
    2. 模板化
    3. 抽象化(组件框架)

过程抽象原则

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

image.png

例如:操作次数限制

  • 一些异步交互
  • 一次性的HTTP请求
 const list = document.querySelector('ul');
  const buttons = list.querySelectorAll('button');
  buttons.forEach((button) => {
    button.addEventListener('click', (evt) => {
      const target = evt.target;
      target.parentNode.className = 'completed';
      setTimeout(() => {
        list.removeChild(target.parentNode);
      }, 2000);
    });
  });

高阶函数

JavaScript的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

  1. Once

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

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