【问题标题】:Best way to compare Objects on the top Level比较顶层对象的最佳方法
【发布时间】:2021-02-17 18:38:30
【问题描述】:

大家好,我目前正在编写一个 Firebase 函数,我必须在其中比较两个对象,这样我就不会陷入无限循环。我的对象如下所示:

{
  id: string
  name: string
  coverURL: string
  year: string
  // part of another object so i minimize my document reads
  relatedItems: {
    id: {
      id: string
      name: string
      coverURL: string
    },
    id: ...
  }
}

如果 id、name、coverURL 或 year 的值发生变化,我只想在 firestore 中做一些事情。这样我就可以更新对象的相关项,而不会陷入无限循环。目前我正在用一个函数检查这个:

function isSame(oldItem: any, newItem: any): boolean {
    if((oldItem.id === newItem.id) && (oldItem.name === newItem.name) && (oldItem.coverURL === newItem.coverURL) && (oldItem.year && newItem.year)) {
        return true;
    } else {
        return false;
    }
}

有没有更好的方法来检查第一层的对象是否相同?

【问题讨论】:

  • 这:“有没有更好的方法来检查第一层的对象是否相同?” - 不是真的。需要进行一些比较。你所做的并没有本质上的错误。
  • 我同意@RandyCasburn,您可以删除不必要的 if else,只需返回测试,您的函数可能是最快的:)

标签: javascript typescript firebase function google-cloud-firestore


【解决方案1】:

你可以像这里一样在谷歌中寻找“浅平等” https://dmitripavlutin.com/how-to-compare-objects-in-javascript/#3-shallow-equality

这个链接也是一种很酷的方式 https://www.samanthaming.com/tidbits/33-how-to-compare-2-objects/#es6-way-for-comparing-2-objects

但是您的解决方案很好。如果你想要其他的写法,你可以这样做

const isSame = (oldItem, newItem) => 
["id", "name", "coverURL", "year"].find(prop => oldItem[prop] !== newItem[prop]) == null;

【讨论】:

  • 感谢您的回答。我会从你的第一个建议中使用某种功能。非常感谢:)
【解决方案2】:

我会遍历对象的键,所以在这种情况下,如果对象相同与否,我们可以知道N 的键数,这样可以避免编写大量的ifs

您必须遍历旧对象和新对象,因为它们可能具有相同长度的键,但它们具有不同的键。

function isSame(oldItem: any, newItem: any): boolean {
  const keysOld = Object.keys(oldItem);
  const keysNew = Object.new(oldItem);

  // if the length of the keys are different, they are different
  if (keysOld.length !== keysNew.length) return false;

  // otherwise we can loop over them to see if the values are the same
  let same = true;
  
  // loop over the old object
  keysOld.forEach(k => {
    // avoid objects/arrays/etc
    if (typeof oldItem[k] === "object") return;

    if (oldItem[k] !== newItem[k]) {
      // if they are different we set the flag to false.
      same = false;
    }
  })
  
  // loop over the new object
  keysNew.forEach(k => {
    // avoid objects/arrays/etc
    if (typeof newItem[k] === "object") return;

    if (oldItem[k] !== newItem[k]) {
      // if they are different we set the flag to false.
      same = false;
    }
  })

  return same;
}

【讨论】:

  • 感谢您的回答!生病可能会使用这个解决方案。但是,如果我检查项目的长度并检查旧项目的键是否等于新项目的键,是否仍然需要反过来检查它?
  • 是的,想想var a = { a: 1, b: {} },然后在第一次迭代中考虑var b = { a: 1, b: 1},你将排除a['b'],因为它是一个对象(记住typeof oldItem[k] === "object"),所以如果你只迭代一次,你会发现对象是相同的,但它们不是,这就是为什么你需要第二次循环它但使用第二个对象作为参考。
【解决方案3】:

这:“如果 id、name、coverURL 或 year 的值发生变化,我只想在 firestore 中做某事。”是基本问题。

如果您已准备好探索该问题的解决方案,并且有兴趣对此(及相关问题)采取更广泛的方法(“反应性”),那么请考虑另一种选择。 p>

此其他选项将使用代理对象。它提供了一种观察变化的方法,而不是一个寻找变化是否发生的解析器函数。对于更复杂的对象来说,这种细微的差别很重要。

代码更加冗长。也许今天的好处对您来说并不明显,但也许这会在未来的某个时间对您产生影响。

Reference 用于代理对象。

  1. 创建一个处理程序(mutationObserver)来处理(在这种情况下)代理对象上属性的setting
    • 在这种情况下,这只是意味着触发一个我们可以监听的自定义事件
  2. 创建代理
  3. 监听要触发的自定义事件
    • 这意味着被监视的属性之一是set(已更改)
  4. 确保您在代理而不是真实对象上进行操作。

const doc = {
  id: 'string',
  name: 'string',
  coverURL: 'string',
  year: 'string',
  relatedItems: {
    id: {
      id: 'string',
      name: 'string',
      coverURL: 'string',
    }
  }
}
const mutationObserver = {
  set: function(target, prop, receiver) {
    const watched = ['id','name','year'];
    if (watched.includes(prop)) {
      document.dispatchEvent(new CustomEvent('doc_change', {
        detail: {
          prop: prop
        }
      }));
    }
  }
}

const docProxy = new Proxy(doc, mutationObserver);

document.addEventListener('doc_change', (e) => {
  console.log('Change to: ', e.detail.prop);
});

docProxy.id = 'fred flintstone';

我希望你觉得这款 segway 很有价值。

【讨论】:

  • 感谢您的回答!每当我有时间处理这个问题时,我都会以正确的方式回到这个解决方案:)
猜你喜欢
  • 1970-01-01
  • 2012-05-14
  • 2012-02-29
  • 2017-11-09
  • 2020-10-23
  • 2015-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多