主题
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个typeof
、constroctor
、instanceof
、Object.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");