介绍

根据模板,自动对一个 JS 对象的字段进行裁剪、添加或更新字段类型。

比如,做一个设置功能,其设置的数据(对象)存储在 localStorage 中。如果对象的字段名称更新了、或增加了一个新的字段、又或者字段的类型变更了,那么 localStorage 存储的对象可能会多出一些旧的(不需要的)字段。打开 F12 清除 localStorage,又会丢失上次设置的数据。

image

在保证其他字段不变化的情况下,对要变更的字段进行裁剪、添加或更新字段类型,refactorObjectProperties 就派上用场了。

演示效果

// 定义一个模板
const settingTempl = {
  themeMode: "dark",
  themeColor: "#409eff",
  openToolKits: true,
  githubPostion: "left",
  openPager: false,
  contentWidth: 50,
  cabinet: {
    left: 0,
    right: 0,
    break: false,
    remote: true,
    pinLeft: false,
    pinRight: false,
    width: 17.5
  },
  // localStorage 中缺少 background 字段,使用 refactorObjectProperties 之后就会自动添加该字段到 localStorage 的对象中,且不影响上面其他字段,也不需要清除 localStorage。
  background: {
    filter: 6,
    src: ""
  }
};

// 获取 localStorage 存储的对象
const store = JSON.parse(localStorage.getItem('setting'));
// 对比模板,裁剪、添加对象字段或更新字段内容
const newStore = refactorObjProps(store, settingTempl);
// 重新存储到 localStorage 中,不影响没有变化的字段
localStorage.setItem('setting', JSON.stringify(newStore));

函数实现

/**
 * 对一个对象的字段进行裁剪或添加
 *
 * @param source 要被裁剪或添加字段的对象
 * @param template 一个对象,根据该模板(对象)对 source 进行裁剪或添加字段
 * @returns
 */
export function refactorObjProps(source, template) {
  if (!source) source = template;
  const sourceKeys = Object.keys(source);
  const templateKeys = Object.keys(template);

  if (sourceKeys.length !== templateKeys.length) {
    if (sourceKeys.length > templateKeys.length) {
      sourceKeys.forEach(sourceKey => {
        const nonentity = templateKeys.find(templateKey => templateKey === sourceKey);
        if (!nonentity) Reflect.deleteProperty(source, sourceKey);
      });
    } else if (sourceKeys.length < templateKeys.length) {
      templateKeys.forEach(templateKey => {
        const nonentity = sourceKeys.find(sourceKey => templateKey === sourceKey);
        if (!nonentity) source[templateKey] = template[templateKey];
        else {
          if (typeof template[templateKey] === "object") {
            refactorObjProps(source[templateKey], template[templateKey]);
          }
        }
      });
    }
  } else {
    templateKeys.forEach(templateKey => {
      if (typeof template[templateKey] === "object") {
        if (typeof source[templateKey] !== "object" || !source[templateKey]) {
          source[templateKey] = template[templateKey];
        }
        refactorObjProps(source[templateKey], template[templateKey]);
      } else if (typeof template[templateKey] !== "object") {
        if (typeof source[templateKey] === "object") source[templateKey] = template[templateKey];
      }
    });
  }
  return source;
}