Skip to content

js工具函数

一、关于函数

1、高阶函数

高阶函数有两个特点:

  • 将函数作为参数的函数(回调)
  • 返回值是一个函数的函数

只要满足以上两个特点中的一个的函数,就是高阶函数

1.1、before函数

高阶函数 before 函数是一个包装函数。也叫装饰器函数,在保证原有函数fn的逻辑不变的前提下,对fn进行包装扩展,以扩展更多功能

js
function fn(a, b, c) {
  console.log("todo...", a, b, c);
}

// 将before挂到Function原型上而不是fn原型上,避免了每次调用都要new 一下fn
Function.prototype.before = function (beforeFn) {
  return (...args) => {
    beforeFn(); // 先执行回调
    this(...args); // 再执行fn方法(因为这里运用了箭头函数,所以this指向before调用者fn)
  };
};

// 使用 -> 返回了一个函数
let newFn = fn.before(() => {
  console.log("fn before...");
});
// 只有调用了返回的函数,才会执行内部逻辑,
newFn("a", "b", "c");
/* 
输出:
    fn before...
    todo... a b c
*/

AOP(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,其实就是给原函数增加一层,不用管原函数内部实现

1.2、类型检测函数

类型检测的方法有4个typeofconstroctorinstanceofObject.prototype.toString.call;

  • typeof 不能区分对象类型
  • controctor 是判断构造函数
  • instanceof 是判断实例
  • Object.protortpe.toString.call 很准确

类型检测方法

js
function isType(value,typeing) {
    return Object.prototype.toString.call(value) === `[object ${typeing}]`
}
isType(123,'Number') // true

缺点: 不方便,不健壮。若是参数typeing传入错误就凉凉

改进 1、不让用户输入类型 2、创建一个utils,封装好各种方法,可以直接调用 3、函数分步传递参数,将函数拆分成功能更具体化的函数

js
function isType(value,typeing) {
    return Object.prototype.toString.call(value) === `[object ${typeing}]`
}

let utils = {};
['Number','String','Boolean','Array','Object'].forEach(typeing=>{
    utils[`is`+typeing] = function(val) {
        return isType(val,typeing)
    }
})

console.log(utils.isString('hello')); // true
console.log(utils.isString(123)); // false

1.3、柯里化函数

柯里化函数也是一个高阶函数,当传出的参数个数没有达到需要的参数总个数时,会将传入的参数进行缓存,直到参数个数满足要求才会输出结果

js
// 这个函数的入参个数是固定的
function add(a, b, c, d, e) {
  return a + b + c + d + e;
}
// 柯理化函数
function curring(fn, arg = []) {
  let len = fn.length; // 实际需要的参数个数
  return (...args) => {
    let arr = [...arg, ...args]; // 我们要收集的每次传入的参数
    if (arr.length === len) {
      return fn(...arr);
    }
    return curring(fn, arr);
  };
}
// 柯理化函数,每次入参都是一个参数
let r = curring(add)(1)(2)(3)(4)(5); // 15
// 偏函数,每次入参个数不定
let p = curring(add)(1, 2)(3, 4, 5); // 15

柯理化类型校验函数

js
// 柯理化函数
function curring(fn, arg = []) {
  let len = fn.length; // 实际需要的参数个数
  return (...args) => {
    let arr = [...arg, ...args]; // 我们要收集的每次传入的参数
    if (arr.length === len) {
      return fn(...arr);
    }
    return curring(fn, arr);
  };
}

// 校验类型方法
function isType(typeing, val) {
  return Object.prototype.toString.call(val) === `[object ${typeing}]`;
}

let utils = {};
["String", "Number", "Boolean"].forEach((typeing) => {
  utils["is" + typeing] = curring(isType)(typeing);
});

utils.isString(123); // true
utils.isBoolean(true); // true

1.4、after函数

应用场景:有一堆异步函数在执行(ajax),我们想在这堆异步函数全部执行完成后进行某项操作,比如进行页面渲染,但是,异步函数返回结果的时间是不确定的,这时,after就派上用场了。

具体实现:

js
const fs = require('fs');
fs.readFile("./a.txt", "utf8", (err, data) => {
  console.log("a.txt读取完毕");
  fn();
});

fs.readFile("./b.txt", "utf8", (err, data) => {
  console.log("b.txt读取完毕");
  fn();
});

// 这里的2表示有两个异步方法,当after被调用了两次后就会执行回调函数
let fn = after(2, () => {
  console.log("文件读取完毕");
  // todo...
});

// after核心方法
function after(timer, callback) {
  return function () {
    if (--timer === 0) {
      callback();
    }
  };
}

二. 常用类型检测

1. 判断可迭代对象

例如:数组、字符串...

js
function isIterable(val) {
  return val !== null && typeof val[Symbol.iterator] === "function";
}

2. 判断Promise

如果一个变量是 Object, 有 then 和 catch 方法, 就认为是 Promise

js
function isPromise(val) {
  return (
    val !== null &&
    typeof val === "object" &&
    typeof val.then === "function" &&
    typeof val.catch === "function"
  );
}

三.其他

判断当前环境的node版本是否符合预期

前提, 项目中的package.json文件中应该存在engines节点

json
{
  "name": "demo",
  "version": "1.0.0",
.......
  "engines": {
    "node": "^12.0.0 || >= 14.0.0"
  }
}

具体检测方法

js
const semver = require("semver"); // 
const chalk = require("chalk"); // 粉笔

// 检查Nodejs版本号
function checkNodeVersion(wanted, id) {
  if (!semver.satisfies(process.version, wanted, { includePrerelease: true })) {
    console.log(
      chalk.red(
        "You are using Node " +
          process.version +
          ", but this version of " +
          id +
          " requires Node " +
          wanted +
          ".\nPlease upgrade your Node version."
      )
    );
    process.exit(1);
  }
}

/* 使用 */
const requiredVersion = require("../package.json").engines.node;
checkNodeVersion(requiredVersion, "demo");