2021SC@SDUSC amis代码分析(6)

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 程序员将泛型用到了极致,一个函数对于所有的数据类型都能兼容支持,需要考虑的方面有很多。在我们自己写代码的过程中,对于不同类型数据的同一功能函数,通常会分开写成多个函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值