以下函数封装参照jQuery源码
首先,将一些原生函数用自己的变量定义
let getProto = Object.getPrototypeOf, // 获取Object.getPrototypeOf方法
class2type = {}, //创建一个空对象
toString = class2type.toString, //获取Object.prototype.toString方法
hasOwn = class2type.hasOwnPrototype,//获取Object.hasOwnPrototype方法
fnToString = hasOwn.toString, //获取Function.prototype.toString方法
ObjectFunctionString = fnToString.call(Object);//获取Object.prototype的字符串
isFunction函数:检测一个对象是否为函数类型
const isFunction = function isFunction(obj) {
return typeof obj === "function" && typeof obj.nodeType !== "number" && typeof obj.item !== "function";
}
isWindow函数:检测一个对象是否为window
const isWindow = function isWindow(obj) {
return typeof obj != null && obj === obj.window; //window对象上有一个window属性,值为window本身
}
toType函数:检测一个值的类型
const toType = function toType(obj) {
if (obj == null) return obj + "";
//Object.prototype.toString返回的值是一个形式为[object xxx]的字符串,用正则表达式获取xxx的内容
let reg = /^\[object ([0-9a-zA-z]+)]$/;
return typeof obj === "object" || typeof obj === "function" ?
reg.exec(toString.call(obj))[1].toLowerCase() :
typeof obj;
}
isArrayLike函数:检测一个对象是否为数组/类数组
const isArrayLike = function isArrayLike(obj) {
let length = !!obj && "length" in obj && obj.length,
type = toType(obj);
if (isFunction(obj) || isWindow(obj)) return false;
//检测普通数组、空数组、类数组
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && (length - 1) in obj;
}
isPlainObject函数:检测一个对象是否为普通对象
const isPlainObject = function isPlainObject(obj) {
let proto, ctor,
type = toType(obj);
if (!obj || type !== "object") return false;
//获取对象的prototype属性
proto = getProto(obj);
//用Object.create(null)创造出来的对象没有prototype属性
if (!proto) return true;
ctor = hasOwn.call(proto, "constructor") && proto.constructor;
//如果obj的构造函数的constructor属性的字符串与Object的字符串相等,则认为obj的构造函数就是Object
return typeof ctor === "function" && fnToString.call(ctor) === ObjectFunctionString;
}
isEmptyObject函数:检测一个对象是否为空对象(没有任何的私有属性,含Symbole类型的属性)
const isEmptyObject = function isEmptyObject(obj) {
if (obj == null || (typeof object !== "object" && typeof object !== "function")) return false;
let keys = Object.keys(obj);
if (typeof Symbol !== "undefined") keys.concat(Object.getOwnPropertySymbols(obj));
return keys.length === 0;
}
isNumeric函数:检测一个值是否为数字
const isNumerc = function isNumeric(obj) {
let type = toType(obj);
return (type === "number" || type === "string") && !isNaN(obj);
}
each函数:迭代数组/对象类型的值
const each = function each(obj, callback) {
let length,
i = 0,
keys;
if (isArrayLike(obj)) {
length = obj.length;
for(; i < length; i++){
if(callback.call(obj[i], obj[i], i) === false) break;
}
} else {
keys = Object.keys(obj);
if(typeof Symbol !== "undefined") keys.concat(Obj.getOwnPropertySymbols(obj));
for(i = 0; i < keys.length; i++){
key = keys[i];
item = obj[key];
if(callback.call(item, item, key) === false) break;
}
}
return obj;
}
clone函数:封装深浅拷贝
const clone = function clone(){
let target = arguments[0],
deep = false,
length = arguments.length,
treated = arguments[length - 1];
if (length >= 2) {
if (typeof target === "boolean"){
deep = target;
target = arguments[1];
}
deep = arguments[1];
}
if (!Array.isArray(treated) || treated.treated) {
treated = [];
treated.treated = true;
}
if (treated.includes(target)) return target;
treated.push(target);
let type = toType(target),
isArray = isArrayLike(target),
isObject = isPlainObject(target);
if (target == null) return target;
let ctor = target.constructor;
if (/^(date|regexp)$/i.test(type)) return new ctor(target);
if (/^(error)$/i.test(type)) return new ctor(target.message);
if (isFunction(target)) return function proxy(...params) {
return target.call(this, ...params);
}
if (!isObject && !isArray) return target;
let result = new ctor();
each(target, (copy, key) => {
if (deep) {
result[key] = clone(copy, deep ,treated);
return;
}
result[key] = copy;
)};
return result;
}