打造自己的JavaScript工具庫

老毛發表於2022-03-01
生產力有兩項,一項是人,一項是工具。工具用得好不好,決定我們下班早不早。

前言

我們在業務開發過程中,經常會重複用到資料型別校驗,日期格式化、資料加密、隨機數生成、節流函式等工具方法,這些工具類函式,適當封裝整理方便拿來就用,可以提高開發效率。

資料型別校驗

也許你喜歡把方法封裝成 ES6 Class 的 method,但是考慮到使用的時候還需要例項化比較麻煩(當然寫成 static method 也可以),不過我還是習慣把方法掛在物件的屬性上,如下:

const Validator = {};

/**
 * 判斷是否是數字, 如:'123.1' 、123.1 都是true
 *
 * @static
 * @param {any} value
 * @returns
 */
Validator.isNumber = (value) => {
  const re = /^[0-9]+\.?[0-9]*$/;
  return re.test(value);
};

/**
 * 整形數字: 2=true; '2'=true
 *
 * @static
 * @param {any} value
 * @returns
 */
Validator.isIntNumber = (value) => {
  if (value === '0' || value === 0) {
    return true;
  }
  const re = /^[1-9]+[0-9]*]*$/;
  return re.test(value);
};

/**
 * 整形數 2 = true; '2' = false
 * 這個方法會嚴格區分string型別的數字
 * @static
 * @param {any} val
 * @returns
 */
Validator.isInt = (val) => {
  if (Validator.isIntNumber(val)) {
    return typeof val === 'number';
  }
  return false;
};

/**
 * 是不是浮點型, 如:'123.1' = false 、123.1 = true
 *
 * @static
 * @param {any} value
 * @returns
 */
Validator.isFloat = (value) => {
  const result = Validator.isNumber(value);
  return result && parseFloat === value;
};

/**
 * 時間戳判斷
 *
 * @static
 * @param {any} value
 * @returns
 */
Validator.isTimestamp = (value) => {
  return typeof value === 'number';
};

/**
 * 驗證手機號
 *
 * @static
 * @param {any} value
 * @returns
 */
Validator.isPhone = (value) => {
  const reg = /^0?(1[34578])[0-9]{9}$/;
  return reg.test(value);
};

/**
 * Url驗證
 *
 * @static
 * @param {any} value
 * @returns
 */
Validator.isUrl = (value) => {
  const strRegex = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/;
  return strRegex.test(value);
};

/**
 * 是否大寫字母
 *
 * @static
 * @param {any} value
 * @returns
 */
Validator.isCapital = (value) => {
  const reg = /[A-Z]/;
  return reg.test(value);
};

/**
 * 是否為空
 *
 * @static
 * @param {any} value
 * @returns
 */
Validator.isEmpty = (value) => {
  // return value?true:false;
  return !!value;
};

/**
 * 是否是一個物件
 *
 * @static
 * @param {any} value 要判斷的物件
 * @returns
 */
Validator.isObject = (value) => {
  const keys = Object.keys(value);
  const values = Object.values(value);
  console.log('is object typeof value is:', typeof value);
  return keys.length > 0 && values.length > 0 && typeof value === 'object';
};

/**
 * 是否為空
 *
 * @static
 * @param {any} value
 * @returns
 */
Validator.isNotEmpty = (value) => {
  return !this.isEmpty(value);
};

Validator.isMobilePhone = (value) => {
  const reg = /^(\+?0?86\-?)?1[345789]\d{9}$/;
  return reg.test(value);
};
/**
 * 是否是monogoDB裡的objectId值
 *
 * @static
 * @param {any} value
 * @returns
 */
Validator.isMongoDBObjectId = (value) => {
  return objectId.isValid(value);
};

/**
 * 此方法特殊方法。obj只能傳一個物件。
 *
 * @static
 * @param {any} obj 物件
 * @param {any} value 值
 */
Validator.isObjectValue = (obj, value) => {
  if (!Validator.isObject(obj)) {
    return false;
  }

  return Object.values(obj).includes(value);
};

/**
 * 檢測郵箱
 * @param email
 * @returns {boolean}
 */
Validator.testEmail = (email) => {
  const reg = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
  return reg.test(email);
};

/**
 * 身份證號碼驗證
 *
 * @param cardNo {String} 證件號碼
 * @returns info {Object} 身份證資訊.
 *
 */
Validator.getIdCardInfo = (cardNo) => {
  const info = {
    isTrue: false, // 身份證號是否有效。預設為 false
    year: null, // 出生年。預設為null
    month: null, // 出生月。預設為null
    day: null, // 出生日。預設為null
    isMale: false, // 是否為男性。預設false
    isFemale: false, // 是否為女性。預設false
  };

  if (!cardNo && cardNo.length !== 15 && cardNo.length !== 18) {
    info.isTrue = false;
    return info;
  }

  if (cardNo.length === 15) {
    const year = cardNo.substring(6, 8);
    const month = cardNo.substring(8, 10);
    const day = cardNo.substring(10, 12);
    const p = cardNo.substring(14, 15); // 性別位
    const birthday = new Date(year,
      parseFloat(month) - 1,
      parseFloat(day), 12, 0, 0, 0);

    // 對於老身份證中的年齡則不需考慮千年蟲問題而使用getYear()方法
    if (birthday.getYear() !== parseFloat(year) ||
      birthday.getMonth() !== parseFloat(month) - 1 ||
      birthday.getDate() !== parseFloat(day)) {
      info.isTrue = false;
    } else {
      info.isTrue = true;
      info.year = birthday.getFullYear();
      info.month = birthday.getMonth() + 1;
      info.day = birthday.getDate();
      if (p % 2 === 0) {
        info.isFemale = true;
        info.isMale = false;
      } else {
        info.isFemale = false;
        info.isMale = true;
      }
    }
    return info;
  }

  if (cardNo.length === 18) {
    const year = cardNo.substring(6, 10);
    const month = cardNo.substring(10, 12);
    const day = cardNo.substring(12, 14);
    const p = cardNo.substring(14, 17);
    const birthday = new Date(year,
      parseFloat(month) - 1,
      parseFloat(day), 12, 0, 0, 0);

    // 這裡用getFullYear()獲取年份,避免千年蟲問題
    if (birthday.getFullYear() !== parseFloat(year) ||
      birthday.getMonth() !== parseFloat(month) - 1 ||
      birthday.getDate() !== parseFloat(day)) {
      info.isTrue = false;
      return info;
    }

    const Wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1]; // 加權因子
    const Y = [1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2]; // 身份證驗證位值.10代表X

    // 驗證校驗位
    let sum = 0; // 宣告加權求和變數
    const _cardNo = cardNo.split('');

    if (_cardNo[17].toLowerCase() === 'x') {
      _cardNo[17] = 10; // 將最後位為x的驗證碼替換為10方便後續操作
    }
    for (let i = 0; i < 17; i++) {
      sum += Wi[i] * _cardNo[i]; // 加權求和
    }
    const i = sum % 11; // 得到驗證碼所位置

    if (_cardNo[17] !== Y[i]) {
      info.isTrue = false;
      return info;
    }

    info.isTrue = true;
    info.year = birthday.getFullYear();
    info.month = birthday.getMonth() + 1;
    info.day = birthday.getDate();

    if (p % 2 === 0) {
      info.isFemale = true;
      info.isMale = false;
    } else {
      info.isFemale = false;
      info.isMale = true;
    }
    return info;
  }
  return info;
};

module.exports = Validator;

日期格式化

需要引入一個package,moment用來處理時間比較方便。

const moment = require('moment');

const DateHandler = {};

/**
 * 獲取現在時間(13位時間戳) 1641185119507
 * @returns {number|*}
 */
DateHandler.getNowTime = () => {
  return new Date().getTime();
};

/**
 * 格式化時間戳
 * @param timestamp
 * @param patten
 */
DateHandler.formatDate = (timestamp, patten) => {
  console.log(timestamp);
  return moment(timestamp).format(patten);
};

/**
 * excel讀取2018/01/01這種時間格式是會將它裝換成數字類似於46254.1545151415
 * @param numb numb是傳過來的整數數字
 * @param format 是之間間隔的符號
 * @returns {string}
 */
DateHandler.formatExcelDate = (numb, format) => {
  const time = new Date((numb - 1) * 24 * 3600000 + 1);
  time.setYear(time.getFullYear() - 70);
  const year = `${time.getFullYear()}`;
  const month = `${time.getMonth() + 1}`;
  const date = `${time.getDate() - 1}`;
  if (format && format.length === 1) {
    return year + format + month + format + date;
  }
  return year + (month < 10 ? `0${month}` : month) + (date < 10 ? `0${date}` : date);
};

/**
 * 毫秒格式化
 * @param t (ms)
 * @returns {string}
 */
DateHandler.formatTime = (t) => {
  const HOUR = 1000 * 60 * 60;
  const d = parseInt(t / (HOUR * 24));
  const h = parseInt((t % (HOUR * 24)) / (HOUR));
  const m = parseInt((t % (HOUR)) / (1000 * 60));
  const s = parseInt((t % (1000 * 60)) / 1000);

  let text = '';
  d && (text += `${d}天`);
  h && (text += `${h}小時`);
  m && (text += `${m}分`);
  s && (text += `${s}秒`);
  return text || '-';
};

module.exports = DateHandler;

隨機數生成

需要用到的package有,randomstring,lodash,dateformat

const randomstring = require('randomstring');
const dateformat = require('dateformat');
const _ = require('lodash');

/**
 * an integer between start and end
 * @param start
 * @param end
 * @returns {number}
 * @constructor
 */
NumHandler.Random = (start, end) => {
  return _.random(start, end);
};

NumHandler.removeEmptyField = (list, field) => {
  list.forEach(v => (v[field].length === 0 ? delete v[field] : this.removeEmptyField(v[field], field)));
  return list;
};

/**
 * 生成隨機編號
 * @param n 位數
 * @param collection
 * @returns {string}
 */
NumHandler.generateRandom = (n, collection = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) => {
  let res = '';
  for (let i = 0; i < n; i++) {
    const id = Math.ceil(Math.random() * (collection.length - 1));
    res += collection[id];
  }
  return res;
};


const Collection_Num = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
NumHandler.generateUUID = () => {
  const Collection_Alpha = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
  return NumHandler.generateRandom(31, Collection_Num.concat(Collection_Alpha));
};

/**
 * 生成訂單編號
 *
 * @static
 */
NumHandler.generateOrderCode = () => {
  const time = dateformat(this.getNowTime(), 'yyyymmddHHMMss');
  const randNumber = this.generateRandom(3, Collection_Num);
  return `${time}${randNumber}`;
};

/**
 * 生成序列號
 *
 * @static
 * @returns
 */
NumHandler.generateSerNum = () => {
  const time = dateformat(this.getNowTime(), 'yyyymmddHHMMss');
  const randomNum = randomstring.generate({ length: 12, charset: 'numeric' });
  return `${time}2${randomNum}`;
};

module.exports = NumHandler;

總結

工欲善其事必先利其器。有了屬於自己的這把利器,也許才能在抗議加班的時候不至於太慫~

相關文章