如何写好JavaScript

101 阅读5分钟

三个原则

写好JavaScript的三个原则:各司其责 组件封装 过程抽象

各司其责

HTML/CSS/JavaScript各司其责

  • HTML -> Structural ; CSS -> Presentational ; JavaScript -> Behavioral
  • 应当避免不必要的由JS直接操作样式
  • 可以用class来表示状态
  • 纯展示类交互应寻求零JS方案

下面是三个版本的例子:深浅色模式切换

fc4607334d4f3c7adbda0778f0972195.png

65a5e6de8bced5029f78004e5ce269af.png

0a5b588e31cf3bb12904600306308128.png

组件封装

组件是指Web页面上抽出来的一个个包含模块(HTML)、样式(CSS)和功能(JS)的单元。好的组件具备封装性、正确性、扩展性、复用性。实现组件的步骤:结构设计、展现效果、行为设计,三次重构:插件化重构、模板化重构、抽象化重构。

  • 结构设计:HTML
  • 展现效果:CSS
  • 行为设计:JS
  1. API(功能),API 设计应保证原子操作,职责单一,满足灵活性。
  2. Event(控制流),使用自定义事件来解耦。
  • 模板化重构
  • 将HTML模板化,更易于扩展
  • 抽象化重构(组件框架)
  • 将通用的组件模型抽象出来

下面是一个轮播图的案例

8cb645c972e8a303c8a3a53cd2718d8f.png

709ff717cd9c67757293095ab3aa6b9c.png

85efc62e6a9cb941551f07db78044f6e.png

820754655853437cafaeed09d8b75b83.png 实现切换行为,设计API,选择与轮播,定义类实现API。

不是很灵活,于是提出插件化

  • 插件化重构,即解耦
  • 将控制元素抽取成插件
  • 插件与组件之间通过依赖注入方式建立联系

8b68489ed0791e83378ac66f49a64021.png 在构造函数定义很多内容,定义原点与选择。

1bc56305f161e554e60891341892f359.png 插件化的过程就是将控制元素给抽象成插件,在插件与组件中建立联系。

过程抽象

过程抽象是指用来处理局部细节控制的一些方法,是函数式编程思想的基础应用。操作次数限制 操作次数限制常用场景有

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

通过高阶函数,以函数作为参数,就能得到写出一个只执行一次或者限制次数的函数,例如下面Once()函数,这个函数的参数是一个函数fn,然后执行时会返回一个函数出去,在返回函数中间进行判断fn是否存在,如果存在则用实际参数执行fn,然后将fn=null这样下次就不会执行该函数。例如下面,我声明了一个show函数,其中求a+b的和,并且打印了字符串,在下面我讲这个函数赋值给foo=once(show),然后调用了三次foo(),控制台中只执行了一次。

function once(fn){ 
    return function(...args){
        if(fn){ //判断函数是否存在,如果存在则用实际参数调用它,然后把它置为空
            const ret = fn.apply(this, args);// 用实际参数执行函数
            fn = null;// 置空,下次就不会执行判断语句里面的内容就不会调用函数
            return ret;// 把fn的结果返回出去
        }
    }
}
function show(a, b) {
    let ans = a + b
    console.log("打一下~");
    return ans
}
let foo = once(show);
console.log(foo(10, 20));//"打一下~ 30

console.log(foo(30, 40));//undeifined
console.log(foo(50, 60));//undeifined

高阶函数

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

节流函数的作用: 假设后台需要记录一个用户的行为,例如鼠标移动,但是用户会经常移动鼠标,即使用户稍微移动下,也会发送很多数据到后台去,这个就会造成很大的带宽浪费,用户移动的鼠标的数据不是说要完全的发送给后台去,我们可以设定一个间隔时间来记录一次数据就可以限制其数据。

节流函数的思路: 使用高级函数思路,以原始函数fn为参数,返回一个函数作为结果,我们会设置一个timer,如果这个timer没有的话就执行fn,同时会给这个timer注册一个setTimeout,在指定的时间后把timer=null,timer存在的时间内,无论怎么调用这个节流函数,因为timer不为空,所以都不会执行fn。

function throttle(fn, time = 500){
  let timer;
  return function(...args){
    if(timer == null){ // 如果timer不为空则不进入判断体,就不会再次执行fn
      fn.apply(this,  args);
      timer = setTimeout(() => {
        timer = null;
      }, time)
    }
  }
}

防抖函数的作用:  当记录鼠标移动的时候,如果我们一直胡乱移动鼠标,是不会记录鼠标,只有当鼠标停止的时候才会记录,例如下面的小鸟,当我们胡乱移动鼠标的时候,它并不会移动,只有当鼠标停止它才会移动过来

3f34fcd5ed87b30ab1b858382be66c6f.png 节流函数的思路:  仍然使用高级函数思路,依然用一个timer来记录,每次移动的时候清除掉上一个timer定时器,然后又给这个timer重新注册一个setTimeout定时器,只有当定时器自动执行结束后才会执行fn

编程范式

编程范式: 包括JavaScript等很多现代脚本语言是混合的编程范式,编程范式是有几种分类的,大的分类分成命令式 和声明式。 命令式 又分成过程式和面向对象; 声明式 又分成逻辑式和函数式; JavaScript这种现代脚本语言是一种混合的编程范式,多少都既带有这种命令式,也带有声明式的特点,所以我们可以通过JS写出符合命令式 风格的代码, 也可以写出声明式风格的代码,命令式 和声明式 没有优劣之分。同时支持两种风格语言让JavaScript的写法更加灵活

总结

这堂课讲的知识非常的多而且杂,但总体分成三个原则写好JavaScript的三个原则:各司其责 组件封装 过程抽象,需要深入、清晰并结构化地阐述重点、经验和最佳实践。