// 判断变量的类型;
const toType = function toType(obj) {
// 因为这里需要匹配[]两个字符,因此需要转义
// \w代表字母数字下划线
// \W代表匹配任意非字母数字下划线
// 两个组合一起,就是获取任意字符序列
let reg = /^\[object ([\w\W]+)\]$/;
if (obj == null) return obj + ""; //传啥返回啥,转换为字符串方便处理
return typeof obj === "object" || typeof obj === "function"
? // 确保toString方法的上下文是obj,返回复杂数据类型(数组也属于对象)
reg.exec(toString.call(obj))[1].toLowerCase()
: typeof obj; //返回基本数据类型
};
// toString方法尝试将一个值转换为字符串
console.log([1, 2].toString()); //1,2
console.log(/^\[object ([\w\W]+)\]$/.exec(toString.call([1, 2, 3]))); //[object Array] Array
console.log(obj.toString()); //[object Object]
console.log(/^\[object ([\w\W]+)\]$/.exec(toString.call({ name: "zq" }))); //[object Object] Object
console.log(/^\[object ([\w\W]+)\]$/.exec(toString.call("1"))); //'[object String]' String
console.log(/^\[object ([\w\W]+)\]$/.exec(toString.call(1))); //[object Number]', 'Number'
console.log(/^\[object ([\w\W]+)\]$/.exec(toString.call(true))); //[object Boolean]', 'Boolean
console.log(/^\[object ([\w\W]+)\]$/.exec(toString.call(null))); //'[object Null]', 'Null'
console.log(/^\[object ([\w\W]+)\]$/.exec(toString.call(undefined))); //[object Undefined]', 'Undefined'
// 判断一个参数是否为函数
const isFunction = function isFunction(obj) {
return (
typeof obj === "function" &&
typeof obj.nodeType !== "number" &&
typeof obj.item !== "function"
);
};
//createElement方法创建一个标签,如果不能识别则创建一个元素<object>,有些时候可能会被浏览器认为是一个函数
// 不论什么类型的元素的nodeType都是number类型
console.log(typeof document.createElement("li").nodeType); //number
// 类数组身上具有item方法,获取第几个元素
console.log(document.getElementsByTagName("li"));
const isWindow = function isWindow(obj) {
return obj != null && obj === obj.window;
};
// 两者属于一个东西
console.log(window.window === window); //true
const isArrayLike = function isArrayLike(obj) {
// 该值必须存在,最后取length的值
let length = !!obj && "length" in obj && obj.length,
type = toType(obj); // 如果是数组,返回的[object Array]经过测试为array
// 如果是一个函数 function(){}其属性上默认存在length属性0
if (isFunction(obj) || isWindow(obj)) return false;
// 因为这里只是判断是否为类数组,所以不需要使用&进行校验
return (
type === "array" ||
length === 0 || //校验空数组情况
(typeof length === "number" && length > 0 && length - 1 in obj) //最后一段代码判断其索引是否有效,常用于处理类数组
);
};
/* 检测数据类型 */
const class2type = {},
toString = class2type.toString, //保存纯粹对象身上的toString方法
hasOwn = class2type.hasOwnProperty; //该方法判断一个方法中是否存在某个私有属性
const isPlainObject = function isPlainObject(obj) {
let proto, Ctor;
// 如果该属性不存在或者其转换后的类型不是对象直接返回false
// 一定需要使用call方法修改this指向,否则第二个Object可能会是Undefined
if (!obj || toString.call(obj) !== "[object Object]") return false;
// 获取对象的原型,使用new Fun定义的实力对象,其原型存在constructor属性,而var o = {}这种格式的constructor则是在顶层Object身上
proto = Object.getPrototypeOf(obj);
// 该对象没有原型代表为纯粹对象
if (!proto) return true;
// 判断该原型是否存在构造函数
Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
// 构造函数需要直接指向顶层Object函数,由谁创建的,构造器指向谁
return typeof Ctor === "function" && Ctor === Object;
};
console.log(isPlainObject({ x: 1 }));
function f() {
this.x = "1";
}
let o = new f();
console.log(f.prototype.constructor === f); //true
let name = Symbol();
let obj = {
x: 1,
[name]: "111",
};
const isEmptyObject = function isEmptyObject(obj) {
// getOwnPropertyNames方法获取所有的键名
// getOwnPropertySymbols方法获取所有的Symbol类型的键名
let keys = Object.getOwnPropertyNames(obj);
if (typeof Symbol !== "undefined")
keys = keys.concat(Object.getOwnPropertySymbols(obj));
return keys.length === 0;
};
const storage = {
set(key, value) {
localStorage.setItem(
key,
JSON.stringify({
time: +new Date(),
value,
})
);
},
get(key, cycle = 2592000000) {
cycle = +cycle;
//如果'123fasfasf'=true ‘123’=false
if (isNaN(cycle)) cycle = 2592000000;
let data = localStorage.getItem(key); //如果没有值,对其进行JSON解析则会报错
if (!data) return null;
let { time, value } = JSON.parse(data);
if (+new Date() - time > cycle) {
storage.remove(key);
return null;
}
return value;
},
remove(key) {
localStorage.removeItem(key);
},
};
const toType = function toType(obj) {
let reg = /^\[object ([\w\W]+)\]$/;
if (obj == null) return obj + "";
return typeof obj === "object" || typeof obj === "function"
? reg.exec(toString.call(obj))[1].toLowerCase()
: typeof obj;
};
const isNumeric = function isNumeric(obj) {
var type = toType(obj);
return (
(type === "number" || type === "string") &&
!isNaN(obj - parseFloat(obj))
);
};
console.log(isNaN(1));
console.log(isNaN("1"));
console.log(isNaN("1b"));
console.log(parseFloat("1"));
console.log(parseFloat(1));
console.log(parseFloat("1basf")); //true
console.log("1basf" - parseFloat("1basf")); //NAN
console.log(isNumeric("1basf")); //false
console.log(isNumeric("1")); //true
console.log(isNumeric(1)); //true
const clearTimer = function clearTimer(timer) {
if (timer) clearTimeout(timer);
return null;
};
const debounce = function debounce(func, wait, immediate) {
if (typeof func !== "function")
throw new TypeError("func is not a function!");
//用户可以不传入时间或立即执行的标识
if (typeof wait === "boolean") {
immediate = wait; // 为true代表立即执行
wait = undefined;
}
wait = +wait;
if (isNaN(wait)) wait = 300;
if (typeof immediate !== "boolean") immediate = false;
let timer = null;
return function operate(...params) {
let now = !timer && immediate; //立即执行的标识
timer = clearTimer(timer);
timer = setTimeout(() => {
if (!immediate) func.call(this, ...params);
timer = clearTimer(timer);
}, wait);
if (now) func.call(this, ...params);
};
};
const throttle = (fn, wait = 300) => {
let previous = new Date();
return function (...params) {
let cur = new Date();
if (cur - previous >= wait) {
fn.call(this, ...params);
previous = cur;
}
};
};
AnimationFramethrottle(fn) {
let lock = false; //防止频繁触发
return function (...params) {
window.requestAnimationFrame(() => {
if (lock) return;
lock = true;
fn.apply(this, params);
lock = false;
});
};
}
const mergeArray = function mergeArray(first, second) {
// 一二步可以理解将数据转换为课操控的类数组
if (typeof first === "string") first = Object(first);
if (typeof second === "string") second = Object(second);
if (!isArrayLike(first)) first = [];
if (!isArrayLike(second)) second = [];
let len = +second.length,
j = 0,
i = first.length;
for (; j < len; j++) {
first[i++] = second[j];
}
first.length = i;
return first;
};
const each = function each(obj, callback) {
// 判断是否为对象或者数组
let isArray = isArrayLike(obj),
isObject = isPlainObject(obj);
if (!isArray && !isObject)
throw new TypeError(
"obj must be a array or likeArray or plainObject"
);
// 回调函数执行对应的操作
if (!isFunction(callback))
throw new TypeError("callback is not a function");
// 如果为数组,则执行对应的操作
if (isArray) {
for (let i = 0; i < obj.length; i++) {
let item = obj[i], //元素值
index = i; //元素下标
// 如果回调函数中返回false则提前结束数组中的数据读取
if (callback.call(item, item, index) === false) break;
}
return obj; //返回数据本身
}
// 如果为对象则执行对应的操作
let keys = Object.getOwnPropertyNames(obj); //获取私有属性名(无法获取symbol)
if (typeof Symbol !== "undefined") // 判断当前环境是否支持Symbol
keys = keys.concat(Object.getOwnPropertySymbols(obj)); //获取私有Symbol属性名
for (let i = 0; i < keys.length; i++) {
let key = keys[i], //键名
value = obj[key]; //键值
if (callback.call(value, value, key) === false) break;
}
return obj; //返回数据本身
};
let res = each([1, 2, 3, 4], (x, y, z) => {
console.log(x, y, z);
});
console.log(res); //[1, 2, 3, 4]
const clone = function clone(...params) {
let target = params[0],
deep = false,
length = params.length,
i = 1,
isArray,
isObject,
result, //最终拷贝的结果
treated; //存储处理过的数据,避免递归操作引起死循环
if (typeof target === "boolean" && length > 1) {
deep = target; // 标志位,是否深拷贝
target = params[1]; //保存实际需要拷贝数据
i = 2;
}
treated = params[i]; //获取已经处理完成的数据
// 使用set结构去重,避免对同一个数据进行递归操作
if (!treated) treated = new Set();
// 如果是已经处理过的数据直接返回
if (treated.has(target)) return target;
//treated,深拷贝的情况下,传入的数据依次取出重新放入set中
// 浅拷贝和深拷贝treated中存储的数据不一样
treated.add(target);
// 校验传递进来的数据是数组还是普通对象
isArray = Array.isArray(target);
isObject = isPlainObject(target);
// 处理null或undefined的情况
if (target == null) return target;
// 两个判断排除特殊情况
// 如果不是数组,不是普通对象,不是函数类型却又是普通对象
if (
!isArray &&
!isObject &&
!isFunction(target) &&
typeof target === "object"
) {
try {
// 将target的值复制到一个新的对象中
return new target.constructor(target);
} catch (_) {
return target;
}
}
// 普通数据的情况下直接返回,如number/string
if (!isArray && !isObject) {
return target;
}
// 创建新的对象引用
/* 这行代码的目的是为了创建一个与 target 具有相同构造函数的新对象,从而保留了对象的类型信息 */
result = new target.constructor();
// 遍历对象或数组中的每一个元素进行拷贝
each(target, (copy, name) => {
if (deep) {
// 深拷贝
result[name] = clone(deep, copy, treated);
return;
}
result[name] = copy; //浅拷贝
});
return result;
};
let obj = { a: 1, b: 2, c: { name: "1" } };
let res = clone(false, obj);
console.log((res.c.name = 1000), obj);
function setId() {
let randomId = "";
for (let i = 1; i <= 32; i++) {
const n = Math.floor(Math.random() * 16.0).toString(16);
randomId += n;
if (i === 8 || i === 12 || i === 16 || i === 20) {
randomId += "-";
}
}
return randomId;
}
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- huatuo0.cn 版权所有 湘ICP备2023017654号-2
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务