limu
Version:
A fast js lib of immutable data, based on shallow copy on read and mark modified on write mechanism
161 lines (134 loc) • 4.32 kB
text/typescript
/*---------------------------------------------------------------------------------------------
* Licensed under the MIT License.
*
* @Author: fantasticsoul
*--------------------------------------------------------------------------------------------*/
import type { AnyObject, DataType, Fn, ObjectLike, Primitive } from '../inner-types';
import { ARR_DESC, desc2dataType, FN_DESC, IS_RAW, MAP_DESC, META_VER, OBJ_DESC, SET_DESC } from './consts';
export const toString = Object.prototype.toString;
const canUseReflect = !!Reflect;
const hasProp = Object.prototype.hasOwnProperty;
export function has(obj: any, key: any) {
if (canUseReflect) {
return Reflect.has(obj, key);
}
return hasProp.call(obj, key);
}
export function deepDrill<T extends ObjectLike>(obj: T, parentObj: any, key: any, subObjCb: (obj: any, parentObj: any, key: any) => void) {
const list: any[] = [];
const innerDeep = (obj: any, parentObj: any, key: any) => {
if (isPrimitive(obj)) {
return;
}
if (list.includes(obj)) {
// 出现循环引用,及时跳出来,避免出现错误:Maximum call stack size exceeded
return;
}
list.push(obj);
subObjCb(obj, parentObj, key);
// const drillThenCb = (obj: any, parentObj: any, key: any) => {
// innerDeep(obj, parentObj, key);
// subObjCb(obj, parentObj, key);
// };
if (Array.isArray(obj)) {
obj.forEach((item: any, idx: number) => {
innerDeep(item, obj, idx);
});
}
// TODO 处理 set
// if (isSet(obj)) {
// obj.forEach((item: any) => {
// subObjCb(item, obj, idx);
// });
// }
if (isMap(obj)) {
obj.forEach((value: any, key: any) => {
innerDeep(value, obj, key);
});
}
if (isObject(obj)) {
Object.keys(obj).forEach((key) => {
innerDeep(obj[key], obj, key);
});
}
};
innerDeep(obj, parentObj, key);
}
export function getValStrDesc(val: any) {
// return Array.isArray(val) ? ARR_DESC : toString.call(val);
return toString.call(val);
}
export function noop(...args: any[]) {
return args;
}
export function isObject(val: any): val is AnyObject {
// attention,null desc is '[object Null]'
return getValStrDesc(val) === OBJ_DESC;
}
export function isMap(val: any): val is Map<any, any> {
return getValStrDesc(val) === MAP_DESC;
}
export function isSet(val: any): val is Set<any> {
return getValStrDesc(val) === SET_DESC;
}
export function isFn(val: any): val is Fn {
return getValStrDesc(val) === FN_DESC;
}
export function getDataType(dataNode: any): DataType {
var strDesc = getValStrDesc(dataNode);
const dataType = desc2dataType[strDesc];
return dataType;
}
export function isPrimitive(val: any): val is Primitive {
const desc = getValStrDesc(val);
return ![OBJ_DESC, ARR_DESC, MAP_DESC, SET_DESC, FN_DESC].includes(desc);
}
export function isPromiseFn(obj: any) {
return obj.constructor.name === 'AsyncFunction' || 'function' === typeof obj.then;
}
export function isPromiseResult(result: any) {
return typeof Promise !== 'undefined' && result instanceof Promise;
}
export function canBeNum(val: any) {
var valType = typeof val;
if (valType === 'number') return true;
if (valType === 'string') return /^[0-9]*$/.test(val);
return false;
}
export function isSymbol(maySymbol: any): maySymbol is symbol {
return typeof maySymbol === 'symbol';
}
/**
* 是否已被 markRaw 标记
*/
export function isMardedRaw(val: any): boolean {
if (!val) return false;
return val[IS_RAW] ?? false;
}
const descProto: Record<string, any> = {
[ARR_DESC]: Array.prototype,
[MAP_DESC]: Map.prototype,
[SET_DESC]: Set.prototype,
[FN_DESC]: Function.prototype,
};
export function injectMetaProto(rawObj: any) {
const desc = getValStrDesc(rawObj);
const rootProto = descProto[desc] || Object.prototype;
const pureObj = Object.create(null);
Object.setPrototypeOf(pureObj, rootProto);
Object.setPrototypeOf(rawObj, pureObj);
return rawObj;
}
export function getProxyVer(mayProxy: any) {
if (!mayProxy) {
return '';
}
return mayProxy[META_VER] || '';
}
export function isPrevVerDraft(mayProxy: any, curVer: string) {
const ver = getProxyVer(mayProxy);
if (!ver) {
return false;
}
return ver !== curVer;
}