url传参前端分割成对象形式
url传参前端分割成对象形式
// An highlighted block
var url ='https://xxxx.com?a=json&b=vue&c=444&d=55555';
function getJson(url){
var Urlh =url.split('?')[1] //['https://xxxx.com','a=json&b=vue&c=444&d=55555']
var reg = /([^?&=]+)=([^?&=]*)/g; //正则
var res= Urlh.match(reg) // [ 'a=json', 'b=vue', 'c=444', 'd=55555' ]
var obj ={};
res.forEach(function(value,index,array){
var tempArr =value.split('=');
var key = tempArr[0];
obj[key] = tempArr[1]
});
return obj;
};
var obj = getJson(url)
console.log('obj: ', obj) // { a: 'json', b: 'vue', c: '444', d: '55555' }
获取css的样式值
//**
- 获取css的样式值
- @param {object}obj 对象
- @param attr 字符串
- @returns {*}
*/
function getCSSAttrValue(obj, attr) {
if(obj.currentStyle){ // IE 和 opera
return obj.currentStyle[attr];
}else {
return window.getComputedStyle(obj, null)[attr];
}
}
let test = document.querySelector('.test')
console.log('getCSSAttrValue(test,"backgroundColor"): ', getCSSAttrValue(test,"backgroundColor")) getCSSAttrValue(test,"backgroundColor"): rgb(255, 192, 203)
获取屏幕的宽度和高度
/**
- 获取屏幕的宽度和高度
- @returns {*}
*/
function client() {
if(window.innerWidth){ // ie9+ 最新的浏览器
return {
width: window.innerWidth,
height: window.innerHeight
}
}else if(document.compatMode === "CSS1Compat"){ // W3C
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
}
}
return {
width: document.body.clientWidth,
height: document.body.clientHeight
}
}
console.log('client(): ', client()) // {width: 967, height: 722}
获取滚动的头部距离和左边距离
/**
- 获取滚动的头部距离和左边距离
- scroll().top scroll().left
- @returns {*}
*/
function scroll() {
if(window.pageYOffset !== null){
return {
top: window.pageYOffset,
left: window.pageXOffset
}
}else if(document.compatMode === "CSS1Compat"){ // W3C
return {
top: document.documentElement.scrollTop,
left: document.documentElement.scrollLeft
}
}
return {
top: document.body.scrollTop,
left: document.body.scrollLeft
}
}
setTimeout(()=>{
console.log('scroll(): ', scroll())
},1000)
时间格式化和获取当前时间
/**
* 时间格式化
* @param oldDate 类型可以是 Date,String,Number。 时间戳(1603164716640)和new Date()
* @param fmt 是格式化的类型:yyyy-MM-dd hh:mm,其中的 yyyy | MM | dd | hh | mm
*/
function formatDate (oldDate, fmt) {
let date = new Date()
if (typeof oldDate === 'string' || typeof oldDate === 'number') {
date = new Date(+oldDate)
} else {
date = oldDate
}
// debugger
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
}
let o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
}
function padLeftZero (str) {
return ('00' + str).substr(str.length)
}
for (let k in o) {
if (new RegExp(`(${k})`).test(fmt)) {
let str = o[k] + ''
fmt = fmt.replace(RegExp.$1,(RegExp.$1.length === 1) ? str : padLeftZero(str))
}
}
return fmt
}
console.log('newDate ', formatDate(new Date(),"yyyy/MM-dd hh:mm")) //newDate 2020/12-31 09:39
console.log('string ', formatDate("1603164716640","yyyy/MM-dd hh:mm")) //string 2020/10-20 11:31
//获取当前的正确时间格式
function getNowFormatDate() {
var date = new Date();
var seperator1 = "-";
var seperator2 = ":";
var month = date.getMonth() + 1;
var strDate = date.getDate();
if (month >= 1 && month <= 9) {
month = "0" + month;
}
if (strDate >= 0 && strDate <= 9) {
strDate = "0" + strDate;
}
var hours = date.getHours();
if(hours >=0 && hours <=9){
hours = "0" + hours;
}
var minutes = date.getMinutes();
if(minutes >=0 && minutes <=9){
minutes = "0" + minutes;
}
var seconds = date.getSeconds();
if(seconds >=0 && seconds <=9){
seconds = "0" + seconds;
}
var currentdate = date.getFullYear() + seperator1 + month + seperator1 + strDate
+ " " + hours + seperator2 + minutes
+ seperator2 + seconds;
return currentdate;
}
// console.log('getNowFormatDate(): ', getNowFormatDate())
判断浏览器环境 手机端判断浏览器类型
/**
* 判断浏览器环境 手机端判断浏览器类型
* 目前主要支持 安卓 & 苹果 & ipad & 微信 & 支付宝 & 是否是手机端。
* @param
* @param
*/
BrowserInfo = {
isAndroid: Boolean(navigator.userAgent.match(/android/ig)),
isIphone: Boolean(navigator.userAgent.match(/iphone|ipod/ig)),
isIpad: Boolean(navigator.userAgent.match(/ipad/ig)),
isWeixin: Boolean(navigator.userAgent.match(/MicroMessenger/ig)),
isAli: Boolean(navigator.userAgent.match(/AlipayClient/ig)),
isPhone: Boolean(/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent))
}
console.log('BrowserInfo.isAndroid: ', BrowserInfo.isAndroid)
console.log('BrowserInfo.isIphone: ', BrowserInfo.isIphone)
console.log('BrowserInfo.isIpad: ', BrowserInfo.isIpad)
console.log('BrowserInfo.isWeixin: ', BrowserInfo.isWeixin)
console.log('BrowserInfo.isAli: ', BrowserInfo.isAli)
console.log('BrowserInfo.isPhone: ', BrowserInfo.isPhone)
深浅拷贝
/**
* 深拷贝
* @param obj
* 方法二
return JSON.parse(JSON.stringify(obj))
深拷贝中地址值 循环引用问题解决:
解决办法是:只需要判断一个对象的字段是否引用了这个对象或这个对象的任意父级即可,可以优化deepClone函数
*/
let objBd = {"q":"","p":false,"bs":"","csor":"0","err_no":0,"errmsg":"","g":[{"type":"his_normal","sa":"h_1","q":"数组降维方法"},{"type":"his_normal","sa":"h_2","q":"数组降维"},{"type":"his_normal","sa":"h_3","q":"常用的js方法"},{"type":"his_normal","sa":"h_4","q":"math.abs函数"},{"type":"his_normal","sa":"h_5","q":"RewriteEngine On RewriteRule ^test\\.html$ test.php"},{"type":"his_normal","sa":"h_6","q":"虚拟机php伪静态"},{"type":"his_normal","sa":"h_7","q":"正则匹配url参数"},{"type":"his_normal","sa":"h_8","q":"正则匹配url"},{"type":"his_normal","sa":"h_9","q":"函数式编程 掘金"},{"type":"his_normal","sa":"h_10","q":"函数式编程"}],"queryid":"0x39364d1dc8ba20"}
function deepClone(obj,map = new Map()) {
var inspectType = inspectTypeFn(obj)
var result;
var oClass = inspectType;
if (oClass === "Object") {
result = {};
} else if (oClass === "Array") {
result = [];
} else {
return obj;
}
if( map.get(obj) ){
return map.get(obj);
}
map.set(obj,result);
for (var key in obj) {
var copy = obj[key];
if (inspectTypeFn(copy) === "Object") {
// result[key] = arguments.callee(copy);//递归调用=》调用自己
result[key] = deepClone(copy,map)
} else if (inspectTypeFn(copy) === "Array") {
// result[key] = arguments.callee(copy);
result[key] = deepClone(copy,map)
} else {
result[key] = obj[key];
}
}
return result;
}
// 深拷贝中地址值 循环引用问题解决:
const obj = {
a:1,
b:2
}
obj.c = obj
console.log('deepClone(obj): ', deepClone(obj))
let newObj = deepClone(objBd) //方法一
let newObj = JSON.parse(JSON.stringify(obj)) //方法二
objBd.g[1].q = '卧槽这个是啥'
console.log('objBd: ', objBd)
console.log('newObj: ', newObj)
浅拷贝可以
let objAssign = {a:1}
let newa = objAssign
或者
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }
/**
* 作用: 获取一个值的原始类型字符串 即使判断各个类型
* Number,Undefined,Null,String,Boolean,Array,Object,Function,Symbol,RegExp
*
*/
const _toString = Object.prototype.toString
function toRawType (value) {
return _toString.call(value).slice(8, -1)
}
function isPlainObject (obj) {
return _toString.call(obj) === '[object Object]'
}
function isRegExp (v) {
return _toString.call(v) === '[object RegExp]'
}
obj 数据类型检查
/**
* obj 类型检查 拓展: js中共有7种数据类型: Number,Undefined,Null,String,Boolean,Object,Symbol))
*/
function inspectTypeFn(o){
if (o === null) return "Null";
if (o === undefined) return "Undefined";
return Object.prototype.toString.call(o).slice(8, -1); //检测类型
}
// console.log('inspectTypeFn(1): ', inspectTypeFn(1))
// console.log('inspectTypeFn(1): ', inspectTypeFn(undefined))
// console.log('inspectTypeFn(1): ', inspectTypeFn(null))
// console.log('inspectTypeFn(1): ', inspectTypeFn('1'))
// console.log('inspectTypeFn(1): ', inspectTypeFn(true))
// console.log('inspectTypeFn(1): ', inspectTypeFn({}) )
// console.log('inspectTypeFn(1): ', inspectTypeFn([]) )
// console.log('inspectTypeFn(1): ', inspectTypeFn(Symbol(1)) )
/**
检查一个值是不是没有定义,这里检查了它是undefined或者null类型,满足其一就表示它已定义,返回true
}
*/
function isUndef (v){
return v === undefined || v === null
}
function isDef (v){
return v !== undefined && v !== null
}
/**
检查一个值的数据类型是不是简单类型(字符串/数字/symbol/布尔)
拓展: js中共有7种数据类型: Number,Undefined,Null,String,Boolean,Object,Symbol
isObject))
}
*/
function isPrimitive (value){
return (
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'symbol' ||
typeof value === 'boolean'
)
}
/**
*
* 作用: 对象的快速检查-这主要是用来将对象从简单值中区分出来
* console.log(typeof null === 'object')
*/
function isObject (obj){
return obj !== null && typeof obj === 'object'
}
/**
* 获取数据类型
* @param {*} data
* @return {string} type
*/
const getDataType = data => {
return Object.prototype.toString.call(data).replace(/^\[object\s(.*)\]$/, '$1').toLowerCase()
}
// let a=[],b={},c='',d=4,e=NaN,f=undefined,g=null,h=function(){},i=Symbol(5),j=/Y{2,4}/,k=new Date();
// console.log('getDataType(a): ', getDataType(a))//array
// console.log('getDataType(b): ', getDataType(b))//object
// console.log('getDataType(c): ', getDataType(c))//string
// console.log('getDataType(d): ', getDataType(d))//Number
// console.log('getDataType(e): ', getDataType(e))//Number
// console.log('getDataType(f): ', getDataType(f))//undefined
// console.log('getDataType(g): ', getDataType(g))//null
// console.log('getDataType(h): ', getDataType(h))//function
// console.log('getDataType(i): ', getDataType(i))//symbol
// console.log('getDataType(j): ', getDataType(j))//regexp
// console.log('getDataType(k): ', getDataType(k))//date
函数柯里化
let toolstr1 = 'div,span,p,li,ul,ol'
function makeMap (str, expectsLowerCase ) {
let map = Object.create(null)
let list = Array.isArray(str) ? str : str.split(',')
for(let i = 0; i<list.length;i++){
map[list[i]] = true
}
return expectsLowerCase ? a=> map[a.toLowerCase()] : a=> map[a]
}
let fun1 = makeMap(toolstr1)
console.log('fun1("p"): ', !!fun1("view")) //fun1("p"): false
匀速动画函数
/**
* 匀速动画函数
* @param {object}obj 对象
* @param {number}target 目标位置
* @param {number}speed 步长
*/
function constant(obj, target, speed) {
clearInterval(obj.timer);
var dir = obj.offsetLeft < target ? speed : -speed;
console.log('dir: ', dir)
obj.timer = setInterval(function () {
obj.style.left = obj.offsetLeft + dir + "px";
if(Math.abs(target - obj.offsetLeft) < Math.abs(dir)){
clearInterval(obj.timer);
obj.style.left = target + "px";
console.log(obj.offsetLeft, target);
if(obj.offsetLeft === target){
constant(animate, 0, 5)
}
}else if(obj.offsetLeft <= 0){
clearInterval(obj.timer);
obj.style.left = 0 + "px";
constant(animate, 800, 5)
}
}, 20);
}
var animate = document.querySelector('.animate')
console.log('constant(obj, target, speed): ', constant(animate, 800, 5))
缓动动画
/**
* 缓动动画
* @param obj 对象
* @param json 可以设置 {top: 40,left:50,opacity:0.5,backgroundColor,zIndex,scrollTop,borderRadius}
*颜色也可以改,但是没有动画效果
* @param fn 回调函数
*/
function buffer(obj, json, fn) {
// 1.1 清除定时器
clearInterval(obj.timer);
// 1.2 设置定时器
var begin = 0, target = 0, speed = 0;
obj.timer = setInterval(function () {
// 1.3.0 旗帜
var flag = true;
for(var k in json){
// 1.3 获取初始值
if("opacity" === k){ // 透明度
begin = parseInt( parseFloat(getCSSAttrValue(obj, k)) * 100);
target = parseInt(parseFloat(json[k]) * 100);
}else if("scrollTop" === k){
begin = Math.ceil(obj.scrollTop);
target = parseInt(json[k]);
}else { // 其他情况
begin = parseInt(getCSSAttrValue(obj, k)) || 0;
target = parseInt(json[k]);
}
// 1.4 求出步长
speed = (target - begin) * 0.2;
// 1.5 判断是否向上取整
speed = (target > begin) ? Math.ceil(speed) : Math.floor(speed);
// 1.6 动起来
if("opacity" === k){ // 透明度
// w3c的浏览器
obj.style.opacity = (begin + speed) / 100;
// ie 浏览器
obj.style.filter = 'alpha(opacity:' + (begin + speed) +')';
}else if("scrollTop" === k){
obj.scrollTop = begin + speed;
}else if("zIndex" === k){
obj.style[k] = json[k];
}else if("backgroundColor" === k){
obj.style[k] = json[k];
}else {
obj.style[k] = begin + speed + "px";
}
// 1.5 判断
if(begin !== target){
flag = false;
}
}
// 1.3 清除定时器
if(flag){
clearInterval(obj.timer);
// 判断有没有回调函数
if(fn){
fn();
}
}
}, 200);
}
var animate = document.querySelector('.animate')
console.log('buffer(obj, target, speed): ', buffer(animate,{top: 0,left:0,borderRadius:'50%',backgroundColor:'pink'},()=>{
console.log('end!: ', 111)
}))
检查是不是一个Promise
/**
* 作用: 检查是不是一个Promise
*
*/
function isPromise (val){
return (
isDef(val) &&
typeof val.then === 'function' &&
typeof val.catch === 'function'
)
}
const promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('成功的结果')
},100)
})
console.log(isPromise(promise)) // true
js类型转换
/**
*
* @param {*} val
* 作用: 把一个值转换成可以渲染的字符串。
*/
function toString (val){
return val == null
? ''
: Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
? JSON.stringify(val, null, 2)
: String(val)
}
let a22 = {name:52}
// console.log('toString(a22): ',typeof toString(a22), toString(a22) ) //toString(a22): string {"name": 52}
/**
*
* @param {*} val
* 作用:把一个值转换成数字,转化成功,返回数字,否则原样返回
*/
function toNumber (val){
const n = parseFloat(val)
return isNaN(n) ? val : n
}
// let a22 = '50.586662211'
// console.log('toNumber(a22): ',typeof toNumber(a22), toNumber(a22) )
移除数组的某一项。如果找到就返回删除的哪一项 改变原数组
/**
*
* @param {*} arr 数组,
* @param {*} item String 数组中的某一项
* 作用: 移除数组的某一项。如果找到就返回删除的哪一项 改变原数组
*/
let arr1 = ['div','span','p','li','ul','ol']
function remove (arr, item){
if(arr.length){
const index = arr.indexOf(item)
if(index> -1){
return arr.splice(index,1)
}
}
}
// console.log('remove(arr1,"li"): ', remove(arr1,"li")) //['li']
// console.log('arr1: ', arr1)//["div", "span", "p", "ul", "ol"]
检查对象中是不是有这个key
/**
* @param {*} obj 对象
* @param {*} item 对象中的key
* 作用:检查对象中是不是有这个key
*/
function hasOwn(obj,key){
return Object.prototype.hasOwnProperty.call(obj,key)
}
// let obj2 ={name:'三哥',age:12}
// console.log('hasOwn(obj2,"name"): ', hasOwn(obj2,"name"), hasOwn(obj2,"work")) //true false
为一个纯函数创建一个缓存的版本。
/**
*
* @param {*} fn 接受一个计算函数,如果之前计算过了就存在里面
* 作用: 为一个纯函数创建一个缓存的版本。
*/
function cached(fn) {
const cache = Object.create(null)
return (function cachedFn (str) {
// console.log('this: ', this) //window
const hit = cache[str]
return hit || (cache[str] = fn(str))//cache = {'7':49}
})
}
let f = function (x) {
return x*x
}
// let k1 = cached(f)
// console.log('k1: ', k1)
// let k2 = k1('7')
// console.log('k2=',k2) //k2= 49
// let k3 = k1('7')
// console.log('k3=',k3) //k3=49
驼峰和大小写转化
/**
* 作用: 将连字符-连接的字符串转化成驼峰标识的字符串
* 解析: 可以通过此例来感受下上面的cached函数的作用,因为cache的参数, 一个转换连字符字符串的函数,是一个很纯很纯的函数,所以可以把它缓存起来。
*
*/
let camelizeRE = /-(\w)/g
const camelize = cached((str)=>{
return str.replace(camelizeRE, (_,c) => c ? c.toUpperCase() : '')
})
// let hello = 'hello-world,bei-jing'
// console.log('camelize(hello): ', camelize(hello))//helloWorld,beiJing
/**
* 作用: 将一个字符串的首字母大写后返回,也是可以被缓存的函数。
*
*/
const capitalize = cached((str)=>{
return str.charAt(0).toUpperCase() + str.slice(1)
})
// console.log('capitalize("hello"): ', capitalize('hello world'))
/**
* 作用: 将一个驼峰标识的字符串转换成连字符-连接的字符串
*/
const hyphenateRE = /\B([A-Z])/g
const hyphenate = cached((str) => {
return str.replace(hyphenateRE, '-$1').toLowerCase()
})
// let hello = 'helloWorld,beiJing'
// console.log('hyphenate(hello): ', hyphenate(hello))
将类数组的对象转换成一个真正的数组
/**
*
* @param {*} list 一个数组
* @param {*} start 起始位置
* 作用: 将类数组的对象转换成一个真正的数组。实际上就是一个元素逐一复制到另一个数组的过程。
* 如果是对象Object 或者是Array 可以用toArrya 如果是数组可以[...伪数组]
* 常见的伪数组有:
函数内部的 arguments
DOM 对象列表(比如通过 document.getElementsByTags 得到的列表)
jQuery 对象(比如 $("div") )
*
*/
function toArray(list,start){
start = start || 0
let i = list.length - start
let ret = new Array(i)
while(i--){
ret[i] = list[ i + start]
}
return ret
}
// var fakeArray = {
// "0": "first",
// "1": "second",
// "2": "third",
// length: 3
// };
// console.log('toArray(fakeArray): ', toArray(fakeArray)) //["first", "second", "third"]
// function con(){
// console.log('arguments: ', [...arguments])
// }
// con('a',1,2,'b')
将属性混入到目标对象中,返回被增强的目标对象。
/**
*
* @param {*} to
* @param {*} _from
* 作用: 将属性混入到目标对象中,返回被增强的目标对象。
* 改变了源对象
*/
function extend (to, _from) {
for (const key in _from) {
to[key] = _from[key]
}
return to
}
// let man = man ={name:'男人', age:20,}
// let woman ={ name:'女人',age:20,fa:'长发',xg:['duobian','meili',wenrong={'A':1}]}
// console.log('extend(woman, man): ',extend(woman, man)) //{name: "男人", age: 20, fa: "长发", xg: Array(3)}
// // man.fa = '短发'
// console.log('man: ', man) //man ={name:'男人', age:20,}
// console.log('woman: ', woman) //{name: "男人", age: 20, fa: "长发", xg: Array(3)}
/**
*
* @param {*} arr
* 作用: 将一个对象数组合并到一个单一对象中去。 且不会有重复key
解析: 函数的输入和输出是这样的:
const arr = [{age: 12}, {name: 'jerry', age: 24}, {major: 'js'}]
const res = toObject(arr)
console.info(res) // {age: 24, name: 'jerry', major: 'js'}
*/
function toObject(arr){
let obj = {}
for(let i =0;i<arr.length;i++){
if(arr[i]){
extend(obj,arr[i])
}
}
return obj
}
// console.log(toObject([{name:'json'},{age:27,job:'1024'},{name:'josnWang'}])) // {name: "josnWang", age: 27, job: "1024"}
判断两个值是否相等。是对象吗?结构相同吗?返回一个元素在数组中的索引
/**
*
* @param {*} a 任何类型
* @param {*} b 任何类型
* 作用: 判断两个值是否相等。是对象吗?结构相同吗?
*/
function looseEqual (a, b){
if (a === b) return true
const isObjectA = isObject(a)
const isObjectB = isObject(b)
if (isObjectA && isObjectB) {
try {
const isArrayA = Array.isArray(a)
const isArrayB = Array.isArray(b)
if (isArrayA && isArrayB) {
return a.length === b.length && a.every((e, i) => {
return looseEqual(e, b[i])
})
} else if (a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime()
} else if (!isArrayA && !isArrayB) {
const keysA = Object.keys(a)
const keysB = Object.keys(b)
return keysA.length === keysB.length && keysA.every(key => {
return looseEqual(a[key], b[key])
})
} else {
return false
}
} catch (e) {
return false
}
} else if (!isObjectA && !isObjectB) {
return String(a) === String(b)
} else {
return false
}
}
// const obj = {
// a:1,
// b:2
// }
// obj.c = obj
// const obj1 = {
// a:1,
// b:2,
// c:obj
// }
// looseEqual(obj,obj1)
// console.log('looseEqual(obj,obj1): ', looseEqual(obj,obj1)) // true
/**
*
* @param {*} arr 数组
* @param {*} val 数组里面的元素
* 作用: 返回一个元素在数组中的索引,-1表示没找到。方法很简单,就是上面looseEqual的一个使用场景。
*/
function looseIndexOf (arr,val){
for (let i = 0; i < arr.length; i++) {
if (looseEqual(arr[i], val)) return i
}
return -1
}
// let arrp = [1,2,3,4,5,6,{s:11},null]
// console.log('arrp.indexOf(2): ', arrp.indexOf({s:11})) //用indexOf 的时候差复杂类型的时候就不一定行
// console.log('looseIndexOf({s:11}): ', looseIndexOf(arrp,{s:11}))
// let arr = [ { name:'jie'},{ name:'b' }, 50,30, 'c']
// console.log('looseIndexOf(arr,50): ', looseIndexOf(arr,{name:'b'}))
复制内容到剪切板
/**
* 复制内容到剪切板
* text: 要复制的内容 callback: 回调
*/
function copyText(text, callback) {
let tag = document.createElement('input')
tag.setAttribute('id', 'cp_hgz_input')
tag.value = text
document.getElementsByTagName('body')[0].appendChild(tag)
document.getElementById('cp_hgz_input').select()
document.execCommand('copy')
document.getElementById('cp_hgz_input').remove()
if (callback) callback(text)
}
对比对象,数组
/**
* 获取数据类型
* @param {*} data
* @return {string} type
*/
const getDataType = data => {
return Object.prototype.toString.call(data).replace(/^\[object\s(.*)\]$/, '$1').toLowerCase()
}
/**
* 对比数据
* @param {*} data1
* @param {*} data2
* @returns {boolean}
*/
function compareData(data1, data2) {
const type1 = getDataType(data1)
const type2 = getDataType(data2)
if (type1 !== type2) return false
if (type1 === 'array') return compareArray(data1, data2)
if (type1 === 'object') return compareObject(data1, data2)
return data1 === data2
}
/**
* 对比数组
* @param {Array} data1
* @param {Array} data2
* @returns {boolean}
*/
function compareArray(data1, data2) {
if (data1.length !== data2.length) return false
let isEqual = true
for (let i in data1) {
const item1 = data1[i]
const item2 = data2[i]
isEqual = compareData(item1, item2)
if (!isEqual) break
}
return isEqual
}
/**
* 对比对象
* @param {Object} data1
* @param {Object} data2
* @returns {boolean}
*/
function compareObject(data1, data2) {
const keysArr1 = Object.keys(data1)
const keysArr2 = Object.keys(data2)
if (keysArr1.length !== keysArr2.length) return false
let isEqual = true
for (let [key, val1] of Object.entries(data1)) {
const val2 = data2[key]
isEqual = compareData(val1, val2)
if (!isEqual) break
}
return isEqual
}
// let a1 = ['a',1,[2,3,4],{name:'a',age:15}]
// let a2 = ['a',1,[2,3,4],{name:'a'}]
// console.log('compareData(a1,a2): ', compareData(a1,a2))