如何写好JavaScript | 青训营

170 阅读3分钟

如何写好 JavaScript

👀 什么才是好的 JavaScript 代码?

Q:什么是 ECMA?

A:📦 ECMAScript(简称ES),它定义了JavaScript的核心规范。ECMAScript规范规定了JavaScript的语法、类型、语义和API,使不同的JavaScript引擎能够相互兼容。

📚 各司其职

让 HTML、CSS 和 JavaScript 职能分离。

例如,写一段 JS,控制一个网页支持浅色和深色两种浏览模式,你会怎么做 🤔?

  • 🔴 初学者(爱好者)可能会直接使用 JS 操作 DOM,判断状态后使用 JS 修改对应元素的样式。
  • 🟡 升级版(工程师)可以选择控制对应元素的 class,以修改样式,这种方法更加简洁,同时有效分隔了 JS 和 CSS 的职能,提高了可读性,也便于后期的维护。
  • 🟢 再升级,可以仅使用 CSS 来实现颜色主题切换(伪类选择器),避免使用 JS 对样式进行操作,进一步提升了可读性。

小节:

  • 🔕 避免不必要的 JS 操作样式
  • 🧰 使用 class 来表示状态
  • 🔮 纯展示类交互寻求零 JS 方案

📦 组件封装

组件是指 Web 页面上抽出来一个个包含模板(HTML)、功能(JS)和样式(CSS)的单元,好的 UI 组件具有正确性、拓展型和复用性。

基本思路

例如:用原生 JS 写一个电商网站的轮播图,应该如何实现?

  • 💪 结构(HTML)

    典型的无序列表结构,使用

      来实现。

    • 🪭 表现(CSS)

      • 使用CSS绝对定位将图片重叠在一个位置
      • 轮播图切换的状态使用修饰符(modlfier)
      • 轮播图的切换动画使用 CSS transition
    • 🤖 行为(JavaScript)

      • API
      • 控制流:使用自定义时间来解耦

    总结:

    • ⚙️ 结构设计

    • 💎 展现效果

    • 🦾 行为设计

      • API(功能)
      • Event(控制流)

    重构:插件化

    插件化就是解耦的过程:

    • 插件化:将控制元素抽取成插件
    • 插件与组件之间通过依赖注入的方式建立联系
    • 模板化:将 HTML 模板化,更易于拓展(参照一些成熟的 JS 框架)
    • 抽象化:将组件通用模型抽象出来

    💢 记住,各司其职 != 不同代码分开写

    永不停止的思考 🤔:有没有进一步优化空间?

    🧸 过程抽象

    应用函数式编程思想。

    🪝 React Hooks 是一种典型的过程抽象。

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

    基本思路

    例如:现在有一个简单的 TodoList 功能,存在条件竞争问题,应该如何修复 🤔?

    高阶函数:once

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

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

    🎁 高阶函数 HOF

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

    常用的高阶函数:

    • once:单次触发
    • throttle:节流
    • debouncd:防抖
    • consumer:同步操作转化为异步
    • lterative(JQuery 时代的产物)

    我们为什么要使用高阶函数 🤔?这需要我们先了解一下纯函数

    💎 纯函数的特点是:

    • 无副作用
    • 与外部状态、调用次数等均无关
    • 结果可预期,输入一定则输出一定

    在我们的库中,应该尽可能的使用纯函数,这样可以提高可维护性。

    编程范式

    命令式与声明式。

    // 命令式,注重怎么做
    let list = [1, 2, 3, 4];
    let mapl = [];
    for(let i = 0; i < list.length; i++) {
        mapl.push(list[i] * 2);
    }
    ​
    // 声明式,注重做什么,相对简洁,具有更强的可拓展性
    let list = [1, 2, 3, 4];
    const double = x => x * 2;
    list.map(double);
    

    总结:

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