JavaScript 编码原则之过程抽象 |  青训营笔记

58 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天,本节课👩🏻‍🏫主要是讲解了hoc的定义,和它的几个例子,当然还有它的作用,我们在以后的代码中要多用hoc函数,同时对于编码风格也得改进,对于命令式和声明式这两种风格,我们要提倡使用声明式。

高阶函数

  • 以函数作为参数
  • 以函数作为返回值
  • 常用于作为函数装饰器 如下图所示,就是一个普通的高阶函数

c5e7b3e0.png

** 常用高阶函数 **

  • Once(只触发一次)
  • Throttle(节流)
  • Debounce(防抖)
  • Consumer / 2
  • Iterative

Once实现:

#!/usr/bin/env bun

type TCallback = (data: any) => void;

interface myEventEmmitter {
  on: (eventName: string, callback: TCallback) => void; // 监听事件
  once: (eventName: string, callback: TCallback) => void; // 监听事件仅一次
  emit: (eventName: string, data: any) => void; //  触发事件
}

class eventEmmitter implements myEventEmmitter {
  events: object;

  constructor() {
    this.events = {};
  }

  on(eventName: string, callback: TCallback) {
    // 事件队列不为空,就先清空下
    if (!this.events) this.events = {};
    // 事件名存在的话,直接push进回调;不存在,则队列只有当前的回调
    if (this.events[eventName]) {
      this.events[eventName].push(callback);
    } else {
      this.events[eventName] = [callback];
    }

    if (eventName !== "newListener") this.emit("newListener", eventName);
  }

  once(eventName: string, callback: TCallback) {
    const vm = this;
    // 只触发一次,便从队列中删除
    function onTime(...args) {
      callback.call(this, ...args);
      vm.off(eventName, onTime);
    }
    vm.on(eventName, onTime);
  }

  emit(eventName: string, ...data: any) {
    // 事件名存在,则触发事件
    if (this.events[eventName]) {
      this.events[eventName].forEach((element) => {
        element.call(this, ...data);
      });
    }
  }

  off(eventName: string, callback: TCallback) {
    if (this.events[eventName]) {
      const index = this.events[eventName].indexOf(callback);
      this.events[eventName].splice(index, 1);
    }
  }
}

const myEvent = new eventEmmitter();

myEvent.on("some-event", (msg) => {
  console.log("i am listening", msg);
});
myEvent.once("some-event", (msg) => {
  console.log("i just listen-once", msg);
});
myEvent.emit("some-event", "listen to me");
myEvent.emit("some-event", "listen to me");

Throttle代码实现:

function throttle(fn, delay) {
  let now = Date.now()

  return function() {
    let cur = Date.now()
    if (cur - now >= delay) {
      now = Date.now()
      return fn.apply(this, arguments)
    }
  }
}

Debonce代码实现:

function debounce(fn, wait) {
    let timer = null
    return function() {
        if(timer) {
            clearTimeout(timer)
            timer = null
        }
        timer = setTimeout(() => {
            fn.apply(this, arguments)
        }, wait)
    }
}

使用高阶函数的好处:

  • 封装基础组件
  • 代码复用,代码模块化
  • 保持业务逻辑模块代码的纯净
  • 符合软件工程的高内聚低耦合

编程范式

  • 命令式
  • 声明式

命令式

const arr = [1, 2, 3]
let arr2 = []
for (let i = 0; i < arr.length; i++) {
    arr2.push(arr[i] * 3)
}

声明式

let arr = [1, 2, 3]
const three = x => x * 3
arr.map(three)