有趣且重要的JS知识合集(12)常用基础算法

有趣且重要的JS知识合集(12)常用基础算法,第1张

我这里将会列出一些常用的关于字符串,数组以及vue等的常用基础算法,会不定时持续更新喔~

1、判断车牌号是否正确(包含新能源车)
/**
 * @param {Object} str
 * 判断车牌号是否正确
 */
export function isCarLicense(str) {
	if (!str) {
		return false
	}
	return /^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$/.test(str);
}
2、时间格式化
/**
 * 时间格式化
 * @param {*} date
 * @param {*} fmt 'yyyy-MM-dd HH:mm:ss'
 */
export function format(date, fmt) {
	const o = {
		'M+': date.getMonth() + 1, // 月份
		'd+': date.getDate(), // 日
		'H+': date.getHours(), // 小时
		'm+': date.getMinutes(), // 分
		's+': date.getSeconds(), // 秒
		'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
		S: date.getMilliseconds() // 毫秒
	}
	if (/(y+)/.test(fmt)) {
		fmt = fmt.replace(RegExp., (date.getFullYear() + '').substr(4 - RegExp..length))
	}
	for (let k in o) {
		if (new RegExp('(' + k + ')').test(fmt)) {
			fmt = fmt.replace(RegExp., RegExp..length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length))
		}
	}
	return fmt
}
3、比较两个字符串是否含有共同的子字符串
/**
 * 比较两个字符串是否含有共同的子字符串
 * @param str1 字符串一
 * @param str2 字符串二
 * @param includeSelf 子字符串是否包括本身
 * @return 比较结果
 */
export function hasSameSubStr(str1, str2, includeSelf = false)
{
	if (!str1.length || !str2.length) return false
	let shortStr = str1.length > str2.length ? str2: str1;
	let longStr = str1.length > str2.length? str1: str2;
	let temp = "";
	
	for(let i = 0; i <= shortStr.length - 2; i++)
	{
		for(let j = i + 2; j <= shortStr.length; j++)
		{
			temp = shortStr.substring(i, j);
			let flag1 = includeSelf && longStr.indexOf(temp) >= 0;
			let flag2 = !includeSelf && temp !== shortStr && longStr.indexOf(temp) >= 0;
			
			if(flag1 || flag2)
			{
				return true;
			}
		}
	}
	return false;
}
4、对象数组根据具体参数去重
/**
 * 对象数组根据具体参数去重
 * @param {*} arr 
 */
export function repeatArr (arr, type) {
	const map = new Map()
	for (let i of arr) {
		if (!map.has(i[type])) {
			map.set(i[type], i)
		}
	}
	return [...map.values()]
}
5、防抖函数

/**
 * 防抖函数(常用于input框搜索情况)
 * @param {*} func 
 * @param {*} delay 
 * @param {*} immediate 
 * @returns 
 */
export function debounce(func, delay, immediate = true) {
  let timer = null
  return function(args) {
    let _this = this
    if (timer) clearTimeout(timer)
    if (immediate) {
      let now = !timer
      timer = setTimeout(() => {
        timer = null
      }, delay)
      now && func.call(_this, args)
    } else {
      timer = setTimeout(() => {
        func.call(_this, args)
      }, delay)
    }
  }
6、节流函数

/**
 * 节流函数(常用于onresize, onmouseover情况)
 * @param {*} func 
 * @param {*} delay 
 * @param {*} immediate 
 * @returns 
 */
export function throttle(func, delay, immediate = true) {
  let timer
  return function(args) {
    let _this = this
    if (immediate) {
      let now = Date.now()
      let prev = 0
      if (now - prev > delay) {
        func.call(_this, args)
        prev = now
      }
    } else {
      if (!timer) {
        timer = setTimeout(() => {
          timer = null
          func.call(_this, args)
        }, delay)
      }
    }
  }
}
7、url中将参数部分转为对象
/**
 * url中将参数部分转为对象,处理的数据必须要有 ?分割
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
	let search = ''
	if (url.indexOf('?') !== -1) {
		search = url.split('?')[1]
	}
	if (!search) return {}

	return JSON.parse(
		'{"' +
			decodeURIComponent(search)
				.replace(/"/g, '\"')
				.replace(/&/g, '","')
				.replace(/=/g, '":"')
				.replace(/\+/g, ' ') +
			'"}'
	)
}
8、base64加解密
/**
 * @param {any} 要加密或解密的数据
 * @returns any.base64 
 */
class Base64 {
    _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
    encode(e) {
      let t = "";
      let n, r, i, s, o, u, a;
      let f = 0;
      e = this._utf8_encode(e);
      while (f < e.length) {
        n = e.charCodeAt(f++); 
        r = e.charCodeAt(f++);
        i = e.charCodeAt(f++);
        s = n >> 2;
        o = (n & 3) << 4 | r >> 4;
        u = (r & 15) << 2 | i >> 6;
        a = i & 63;
        if (isNaN(r)) {
            u = a = 64
        } else if (isNaN(i)) {
            a = 64
        }
        t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a)
      }
      return t
    }
    decode(e) {
      let t = "";
      let n, r, i;
      let s, o, u, a;
      let f = 0;
      e=e.replace(/[^A-Za-z0-9+/=]/g,"");
      while (f < e.length) {
          s = this._keyStr.indexOf(e.charAt(f++));
          o = this._keyStr.indexOf(e.charAt(f++));
          u = this._keyStr.indexOf(e.charAt(f++));
          a = this._keyStr.indexOf(e.charAt(f++));
          n = s << 2 | o >> 4;
          r = (o & 15) << 4 | u >> 2;
          i = (u & 3) << 6 | a;
          t = t + String.fromCharCode(n);
          if (u != 64) {
              t = t + String.fromCharCode(r)
          }
          if (a != 64) {
              t = t + String.fromCharCode(i)
          }
      }
      t = this._utf8_decode(t);
      return t
    }
    _utf8_encode(e) {
      e = e.replace(/rn/g, "n");
      let t = "";
      for (let n = 0; n < e.length; n++) {
        let r = e.charCodeAt(n);
        if (r < 128) {
            t += String.fromCharCode(r)
        } else if (r > 127 && r < 2048) {
            t += String.fromCharCode(r >> 6 | 192);
            t += String.fromCharCode(r & 63 | 128)
        } else {
            t += String.fromCharCode(r >> 12 | 224);
            t += String.fromCharCode(r >> 6 & 63 | 128);
            t += String.fromCharCode(r & 63 | 128)
        }
      }
      return t
    }
    _utf8_decode(e) {
      let t = "";
      let n = 0;
      let r = 0;
      let c1 = 0;
      let c2 = 0;
      while (n < e.length) {
          r = e.charCodeAt(n);
          if (r < 128) {
              t += String.fromCharCode(r);
              n++
          } else if (r > 191 && r < 224) {
              c2 = e.charCodeAt(n + 1);
              t += String.fromCharCode((r & 31) << 6 | c2 & 63);
              n += 2
          } else {
              c2 = e.charCodeAt(n + 1);
              c3 = e.charCodeAt(n + 2);
              t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
              n += 3
          }
      }
      return t
  }
}

export default Base64

// 调用方式
new Base64().encode('xxx')
9、定时器类
/**
 * 定时器类
 */
function Timer() {
	this._id = null // 该类唯一id
	this.timeId = null // 该类唯一定时id
	this.func = null // 执行用户自定义回调函数
}

/**
 * 递归定时器
 * @param {Function} func 用户自定义回调函数
 * @param {Number} interval 延时时间
 * @param {Boolean} flag true => setTimeout, false => setInterval, 默认为 true
 * @param {Boolean} immediate 是否立即执行,默认为 false
 * @returns
 */
Timer.prototype.repeat = function(func, interval, flag = true, immediate = false) {
	// 实例无回调函数 则初始化回调函数
	if (this.func === null) {
		this.func = func
	}

	// 立即执行函数
	if (immediate) {
		func()
	}

	this.timeId = setTimeout(() => {
		func()
		if (!flag) {
			// 确保repeat中只立即执行一次用户自定义回调函数
			this.repeat(func, interval, flag)
		}
	}, interval)
}

// 清除定时器
Timer.prototype.clear = function() {
	if (this.timeId) {
		console.log('clear timer', this.timeId)
		clearTimeout(this.timeId)
		this.timeId = null
	} else {
		console.log('目前定时器为null ')
	}
}

export default Timer

// 调用方式
this.timer = new Timer()
this.timer.repeat(
		() => {
            // 要执行的逻辑
			},
		1000,
		false,
		false
	)
10、身份z号验证
/**
 * 身份z号验证
 */
export const checkIdCard = (value, callback) => {
  if (!value) {
    return callback(new Error('身份z号不能为空'))
  }
  else {
    let reg = /(^\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$)|(^\d{6}(18|19|20)\d{2}(0[1-9]|10|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)$)/
    if(reg.test(value)){
      callback();
    }
    else{
      return callback(new Error('身份z号格式不正确'))
    }
  }
}
11、手机号验证
/**
 * 手机号验证
 */
export const checkPhoneNumber = (value, callback) => {
  if (!value) {
    return callback(new Error('手机号不能为空'))
  }
  else {
    let reg = /^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8}$/
    if(reg.test(value)){
      callback();
    }
    else{
      return callback(new Error('手机号格式不正确'))
    }
  }
}
12、阿拉伯数字转为汉字
/**
 * 阿拉伯数字转为汉字
 */
export function formatNumber(number) {
	const chnNumChar = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
	const chnUnitSection = ['', '万', '亿', '万亿', '亿亿']
	const chnUnitChar = ['', '十', '百', '千']

	// 节内转换算法
	function SectionToChinese(section) {
		let strIns = ''
		let chnStr = ''
		let unitPos = 0
		let zero = true
		while (section > 0) {
			const v = section % 10
			if (v === 0) {
				if (!zero) {
					zero = true
					chnStr = chnNumChar[v] + chnStr
				}
			} else {
				zero = false
				strIns = chnNumChar[v]
				strIns += chnUnitChar[unitPos]
				chnStr = strIns + chnStr
			}
			unitPos++
			section = Math.floor(section / 10)
		}
		return chnStr
	}
	// 转换算法主函数
	function NumberToChinese(num) {
		let unitPos = 0
		let strIns = ''
		let chnStr = ''
		let needZero = false

		if (num === 0) {
			return chnNumChar[0]
		}
		while (num > 0) {
			const section = num % 10000
			if (needZero) {
				chnStr = chnNumChar[0] + chnStr
			}
			strIns = SectionToChinese(section)
			strIns += section !== 0 ? chnUnitSection[unitPos] : chnUnitSection[0]
			chnStr = strIns + chnStr
			needZero = section < 1000 && section > 0
			num = Math.floor(num / 10000)
			unitPos++
		}
		return chnStr
	}
	return NumberToChinese(number)
}
13、深拷贝
/**
 * 深拷贝
 */
export const deepClone = obj => {
	const _toString = Object.prototype.toString

	// null, undefined, non-object, function
	if (!obj || typeof obj !== 'object') {
		return obj
	}

	// DOM Node
	if (obj.nodeType && 'cloneNode' in obj) {
		return obj.cloneNode(true)
	}

	// Date
	if (_toString.call(obj) === '[object Date]') {
		return new Date(obj.getTime())
	}

	// RegExp
	if (_toString.call(obj) === '[object RegExp]') {
		const flags = []
		if (obj.global) {
			flags.push('g')
		}
		if (obj.multiline) {
			flags.push('m')
		}
		if (obj.ignoreCase) {
			flags.push('i')
		}

		return new RegExp(obj.source, flags.join(''))
	}

	const result = Array.isArray(obj) ? [] : obj.constructor ? new obj.constructor() : {}

	for (const key in obj) {
		result[key] = deepClone(obj[key])
	}

	return result
}
14、对象数组差异对比(自用dom-diff)
/**
   * before => 差异前数组 type: Array<{id: number, name: string, pid: number, nodeType: number, children: Array[]}>
   * after => 差异后数组 type: Array<{id: number, name: string, pid: number, nodeType: number, children: Array[]}>
   * type => 用于标识两对象不同的地方, 默认为id
   */
  export function compareArray(before, after, type = 'id') {
    const res = {
      add: [], // 新增
      remove: [], // 删除
      update: [] // 更新
    }
    const compareMap = new Map()
    for (let i = 0; i < before.length; i++) {
      compareMap.set(before[i][type], before[i])
      if (before[i].children && before[i].children.length > 0) {
        compareMap.get(before[i][type]).children = before[i].children
      }
    }
    // 差异比较 compareMap中保存的是before有的而after不存在的
    for (let i = 0; i < after.length; i++) {
      if (!compareMap.has(after[i][type])) {
        res.add.push(after[i])
      } else {
        const beforeChild = compareMap.get(after[i][type]).children
        if (beforeChild.length) {
        const afterChild = after[i].children
        const resVal = {
          id: after[i].id,
          name: after[i].name,
          nodeType: after[i].nodeType,
          children: []
        }
        for (let j = 0; j < beforeChild.length; j++) {
          if (!afterChild[j].checked) {
            resVal.children.push({
              checked: afterChild[j].checked,
              id: afterChild[j].id,
              name: afterChild[j].name,
              pid: afterChild[j].pid
            })
          }
        }
        res.update.push(resVal)
        }
        compareMap.delete(after[i][type])
      }
    }
    compareMap.forEach((value, key, map) => {
      res.remove.push(value)
    })
    return res
  }
15、全局事件bus
import Vue from 'vue'

/**
 * 全局事件bus ,每一次事件监听后需要在beforeDestroy中取消监听 this.$notifiy.off(type),否则会重复注册,造成不可预知的错误
 */
class Notify {
	static eventBus = new Vue()

	static events = []

	static send(type, data) {
		Notify.eventBus.$emit(type, data)
	}

	static on(type, callback) {
		if (Notify.events.includes(type)) {
			return
		}
		Notify.events.push(type)
		Notify.eventBus.$on(type, res => {
			callback(res ? res : null)
		})
	}

	static off(type) {
		if (Notify.events.includes(type)) {
			Notify.events = Notify.events.filter(i => i !== type)
			Notify.eventBus.$off(type)
		} else {
			console.warn(`EventBus不存在type${type}`)
		}
	}
}

export default Notify

// 调用方式
this.$notify.on('xxx', () => {})
this.$notify.off('xxx')
16、全屏控制
/**
 * 实现打开、退出全屏
 */
export const FullScreen (el) {
	/* eslint-disable */
	const isFullscreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen
	if (!isFullscreen) {
		// 进入全屏,多重短路表达式
		;(el.requestFullscreen && el.requestFullscreen()) ||
			(el.mozRequestFullScreen && el.mozRequestFullScreen()) ||
			(el.webkitRequestFullscreen && el.webkitRequestFullscreen()) ||
			(el.msRequestFullscreen && el.msRequestFullscreen())
	} else {
		// 退出全屏,三目运算符
		document.exitFullscreen
			? document.exitFullscreen()
			: document.mozCancelFullScreen
			? document.mozCancelFullScreen()
			: document.webkitExitFullscreen
			? document.webkitExitFullscreen()
			: ''
	}
}
17、复杂密码校验
/**
 * 验证密码 必须包含数字、大小写字母、特殊符号,密码长度在 10 到 20 个字符
 */
export const validatePwd (value, callback) {
	if (!value) {
		return callback(new Error('密码不能为空'))
	} else if (value.length < 10 || value.length > 20) {
		return callback(new Error('密码长度应在 10 到 20 个字符'))
	} else {
		const reg = /(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[^a-zA-Z0-9]).{10,20}/
		if (reg.test(value)) {
			callback()
		} else {
			return callback(new Error('密码必须包含大小写字母、数字、特殊字符4种'))
		}
	}
}
18、async/await异常抛出
/**
 * async/await 错误异常抛出
 */
export function to(promise: Promise) {
  return promise.then((data: any) => [null, data]).catch((err: any) => [err])
}

// 调用方式
let [result_err, result] = await to(getApi())
19、数组转化为树形结构
/**
 * 数组转化为树形结构(常用于后台菜单数组转换成树形结构)
 */
export function arrToTree(data) {
  let result = []
  let map = new Map()
  data.forEach(item => {
    // 存入字典集里
    map.set(item.id, item)
  })
  data.forEach(item => {
    // 判断字典集里是否有该键
    let parent = map.get(item.pid)
    if (parent) {
      // ?. 可选链 *** 作符,常用于判断对象里是否有该属性
      // ?? 合并 *** 作符 或等于||,但是不会对左边值进行处理
      (parent?.children??(parent.children = [])).push(item)
    } else {
      result.push(item)
    }
  })
  return result
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/946317.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-18
下一篇 2022-05-18

发表评论

登录后才能评论

评论列表(0条)

保存