JavaScript 编码原则 | 青训营笔记

43 阅读2分钟

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

基本原则

  • 各司其职 - 保证 HTML、CSS、JavaScript 职能分离
  • 组件封装 - 正确性、扩展性、复用性
  • 过程抽象 - 函数式编程思想

各司其职 - 浅色主题和深色主题切换

利用JS直接修改页面整体样式 style 属性

利用JS修改页面级元素 class 类属性

利用checkbox伪类状态结合选择器实现

建议

  • HTML、CSS、JavaScript各司其职
  • 避免直接用JS操作样式
  • 使用class来表示状态
  • 纯展示类交互尽量减少JS的使用,寻求零JS方案

组件封装 - 轮播图

html结构 ul-li 即使用无序列表设置样式 css 样式,支持自动播放 js 支持点击跳转 (触发自定义事件,并监听自定义事件)

基本方法

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

解耦-插件化

控制元素抽取成插件 插件与组件之间通过依赖注入的方式

解耦-模板化

将 HTML 模板化,更易于扩展

抽象化

将通用的组件模型抽象化,即形成组件框架

设计原则

封装性、正确性、扩展性、复用性

实现组件步骤

结构设计、展现效果、行为设计

过程抽象

黑箱思想

利用函数式编程方法

高阶函数 HOF

  • 以函数为参数
  • 以函数为返回值
  • 常作为函数装饰器
function HOF (fn) {
  return function (...args) {
    return fn.apply(this, args)
  }
}

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

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

function Debounce (fn, dur = 1000) {
  let timer = null
  return function () {
    clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(this, arguments)
    }, dur)
  }
}

function Consumer (fn, time) {
  let tasks = []
  let timer = null
  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)
    }
  }
}

function Iterative (fn) {
  const isIterable = obj => obj != null && typeof obj[Symbol.iterator] === 'function'

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

纯函数

  • 不应修改程序的状态或引起副作用,不影响外部变量
  • 不使用外部变量,即自包含
  • 函数输出仅与函数输入有关,其对任一给定的输入有唯一确定的输出

编程范式

命令式 imperative

switcher.onclick = function(evt){
  if(evt.target.className === 'on'){
    evt.target.className = 'off'
  }else{
    evt.target.className = 'on'
  }
}

声明式 declarative

function toggle(...actions){
  return function(...args){
    let action = actions.shift()
    actions.push(action)
    return action.apply(this, args)
  }
}

switcher.onclick = toggle(
  evt => evt.target.className = 'off',
  evt => evt.target.className = 'on',
)