2021SC@SDUSC
概述
本周继续分析 amis 的 helper 包,主要学习对于对象的一系列判断函数。
rmUndefined
去除 obj 中的空属性,并返回一个新对象(obj 本身不改变)
export function rmUndefined(obj: PlainObject) {
const newObj: PlainObject = {};
// 基本对象
if (typeof obj !== 'object') {
return obj;
}
const keys = Object.keys(obj); // obj 的属性名数组
keys.forEach(key => { // 遍历
// 属性值不为空时,将该属性添加到 newObj 中
if (obj[key] !== undefined) {
newObj[key] = obj[key];
}
});
return newObj;
}
isObjectShallowModified
判断对象是否发生改变。
// 当不考虑 strictMode & ignoreUndefined 时
// 可不可以使用以下方式:
/*
(prev,next) => {
return JSON.stringify(prev) === JSON.stringify(next);
}
*/
export function isObjectShallowModified(
prev: any, // 原先的对象
next: any, // 之后的对象
strictMode: boolean = true, // 是否为严格模式
ignoreUndefined: boolean = false, // 是否忽略空值属性
statck: Array<any> = []
): boolean {
// prev 与 next 都是数组类型
if (Array.isArray(prev) && Array.isArray(next)) {
return prev.length !== next.length // 长度不同
? true // 因为 Array 是简单对象,数组长度发生变化,属于浅变化
: prev.some((prev, index) => // 长度没有变化时,需逐个判断两个数组的元素是否发生变化,之一变化则属于浅变化
isObjectShallowModified(
prev,
next[index],
strictMode,
ignoreUndefined,
statck
)
);
// prev 与 next 都是非法字符,未发生变化
} else if (isNaN(prev) && isNaN(next)) {
return false;
} else if (
// 当 prev 与 next 其中之一为 null 或不为 object 或被 mbox 所观察的数据
null == prev ||
null == next ||
!isObject(prev) ||
!isObject(next) ||
isObservable(prev) ||
isObservable(next)
) {
// 在 strictMode 下直接比较即可
return strictMode ? prev !== next : prev != next;
}
// 以下是两者都是对象的情况
// 根据 ignoreUndefined 选择是否去除两者中的空属性
if (ignoreUndefined) {
prev = rmUndefined(prev);
next = rmUndefined(next);
}
// 两者的属性名数组
const keys = Object.keys(prev);
const nextKeys = Object.keys(next);
if (
keys.length !== nextKeys.length || // 属性数量不同
keys.sort().join(',') !== nextKeys.sort().join(',') // 属性名不同
) {
return true;
}
// 避免循环引用死循环。// statck 中还不包含 prev 对象
if (~statck.indexOf(prev)) {
return false;
}
statck.push(prev); // 装入
// 运行自此说明 prev,next 自身属性数量及种类未发生变化,现在判断各属性值是否发生了变化
for (let i: number = keys.length - 1; i >= 0; i--) {
let key = keys[i];
if (
isObjectShallowModified(
prev[key],
next[key],
strictMode,
ignoreUndefined,
statck
)
) {
return true;
}
}
return false;
}
isArrayChildrenModified
判断是否为数组对象发生改变,本函数其实是isObjectShallowModified
的化简。
export function isArrayChildrenModified(
prev: Array<any>,
next: Array<any>,
strictMode: boolean = true
) {
if (!Array.isArray(prev) || !Array.isArray(next)) {
return strictMode ? prev !== next : prev != next;
}
if (prev.length !== next.length) {
return true;
}
for (let i: number = prev.length - 1; i >= 0; i--) {
if (strictMode ? prev[i] !== next[i] : prev[i] != next[i]) {
return true;
}
}
return false;
}
immutableExtends
将 from 对象扩展到 to 上,from 本身不发生变化
export function immutableExtends(to: any, from: any, deep = false) {
// 不是对象,不可以merge
if (!isObject(to) || !isObject(from)) {
return to;
}
let ret = to;
// 遍历所有 from 上的属性
Object.keys(from).forEach(key => {
const origin = to[key];
const value = from[key];
// todo 支持深度merge
if (origin !== value) {
// 一旦有修改,就创建个新对象。
ret = ret !== to ? ret : {...to};
ret[key] = value;
}
});
return ret;
}
总结
从上面列出的几个函数可以明显地判断,amis 程序员将泛型用到了极致,一个函数对于所有的数据类型都能兼容支持,需要考虑的方面有很多。在我们自己写代码的过程中,对于不同类型数据的同一功能函数,通常会分开写成多个函数。