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

本文是2021SC@SDUSC的一篇博客,探讨了如何在ReactJS中处理多级原型链上的属性增删查改。通过讲解keyToPath、getVariable、setVariable、deleteVariable和hasOwnProperty等函数,阐述了如何对复杂对象进行深度操作。学习这些内容有助于深化对原型链的理解,解决实际开发中的难题。
摘要由CSDN通过智能技术生成

2021SC@SDUSC

概述

本周继续分析 helper 工具包。主要学习了对多级原型链上的多级属性进行增删查改的操作。

keyToPath

该函数可以将例如像 a.b.c 或 a[1].b 的字符串转换为路径数组。用于将对象属性的链式调用转化成逐级调用,便可遍历的对调用过程加以中层判断。

export const keyToPath = (string: string) => {
  const result = [];
  if (string.charCodeAt(0) === '.'.charCodeAt(0)) {
    result.push('');
  }
  // 正则匹配
  string.replace(
    new RegExp(
      '[^.[\\]]+|\\[(?:([^"\'][^[]*)|(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))',
      'g'
    ),
    (match, expression, quote, subString) => {
      let key = match;
      if (quote) {
        key = subString.replace(/\\(\\)?/g, '$1');
      } else if (expression) {
        key = expression.trim();
      }
      result.push(key);
      return '';
    }
  );
  return result;
};

示例:

keyToPath('a.b.c');
// -> ['a','b','c']
keyToPath('a[1].b.c');
// -> ['a','1','b','c']

getVariable

该函数是在data的属性中找 key 属性或将key分割后在data的各属性中一级一级地寻找对应属性,canAccessSuper表示是否能在这些对象的原型链上找该属性。

export function getVariable(
  data: {[propName: string]: any},
  key: string | undefined, // key 可以是一个多级属性值
  canAccessSuper: boolean = true
  // 可以推断出 canAccessSuper 参数的作用:属性是否可以来自于原型链
): any {
  if (!data || !key) {
    return undefined;
    // 如果可以来自于原型链的话,判断 data 以及 data 的原型链上是否包含 key 属性
    // 否则,判断data的自身属性中是否包含 key 属性
  } else if (canAccessSuper ? key in data : data.hasOwnProperty(key)) {
    // 包含,即返回该属性值
    return data[key];
  }
  // 将 key 属性划分成属性列表
  // reduce 上一次迭代的返回值做为下一次迭代的输入值
  return keyToPath(key).reduce(
    (obj, key) =>
      obj && // obj 不为空 且为对象 且在该对象上包含 key 属性
      typeof obj === 'object' &&
      (canAccessSuper ? key in obj : obj.hasOwnProperty(key))
        // 返回该属性值,下一次迭代时再次下级属性
        ? obj[key]
        : undefined, // 若其中有一级为 undefined,则之后的各级均为 undefined
    data // 初始值为data
  );
}

setVariable

该函数用于在data中寻找一级一级地寻找key属性,没有就创建

export function setVariable(
  data: {[propName: string]: any},
  key: string,
  value: any
) {
  // data 为空时赋值为空对象
  data = data || {};

  if (key in data) {
    // 当 key 包含在 data 的自身属性或是在原型链上时,直接赋值
    data[key] = value;
    return;
  }
  // 将 key 属性分割成各级属性
  const parts = keyToPath(key);
  // 最后一级属性
  const last = parts.pop() as string;
  // 依次寻找 目标 partKey 在 data 下级对象中对应的属性值
  while (parts.length) {
    // 从头部弹出一个 key,作为本次迭代的目标属性
    let key = parts.shift() as string;
    // 如果 data[key] 是原生对象, Number | string 
    if (isPlainObject(data[key])) {
      // 将其包装成一个对象,为了使用它的指针,才能继续找下一级
      data = data[key] = {
        ...data[key]
      };
    // 如果 data[key] 是一个数组
    } else if (Array.isArray(data[key])) {
      data[key] = data[key].concat(); // 这一个不知道有什么意义?
      data = data[key];
    } else if (data[key]) {
      // throw new Error(`目标路径不是纯对象,不能覆盖`);
      // 强行转成对象
      data[key] = {};
      data = data[key];
    } else {
      data[key] = {}; // 其他情况即没有 key 时, 创建 key 属性
      data = data[key];
    }
  }
  // 将最后一级属性赋值为 value; 不管它存不存在,不存在即创建
  data[last] = value;
}

deleteVariable

该函数用于删除对象的多级属性

export function deleteVariable(data: {[propName: string]: any}, key: string) {
  // data为空
  if (!data) {
    return;
    // data自身属性中包含 key
  } else if (data.hasOwnProperty(key)) {
    delete data[key];
    return;
  }

  // key 属性切割
  const parts = keyToPath(key);
  const last = parts.pop() as string; // 最后的目标属性

  while (parts.length) {
    let key = parts.shift() as string; // 从头部弹出
    // 存在该一级的属性,才继续寻找下一级属性
    // 不存在则直接 break
    if (isPlainObject(data[key])) {
      data = data[key] = {
        ...data[key]
      };
    } else if (data[key]) {
      throw new Error(`目标路径不是纯对象,不能修改`);
    } else {
      break;
    }
  }
  // data 不为空 且自身属性包含 last 目标属性
  if (data && data.hasOwnProperty && data.hasOwnProperty(last)) {
    delete data[last]; // 删除
  }
}

hasOwnProperty

判断data对象自身是否含有多级属性key

export function hasOwnProperty(
  data: {[propName: string]: any},
  key: string
): boolean {
  const parts = keyToPath(key);

  while (parts.length) {
    let key = parts.shift() as string;
    if (!isObject(data) || !data.hasOwnProperty(key)) {
      return false;
    }
    data = data[key];
  }
  return true;
}

总结

从上述对复杂对象多级原型链上的多级属性进行增删改查的代码思路来看,这一部分的内容是很复杂的,对原型链不熟悉的话很难理解一层层的递归过程及原理。学习完后,我对原型链操作又有了更深层次的了解,相信今后在处理此类问题的时候不在那么手足无措了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值