检查 n-depth POJO 中的所有属性都不为空

Check all properties are not null in n-depth POJO

我需要一个函数,如果每个 child 满足一个条件,它接受任何 object 和 returns true/false。目前该条件是 属性 为真。所以 null 和 undefined 应该 return false,但是 false 的值是 pass.

我正在做的项目是在 Typescript 中,但这也适用于 vanilla JS,我也可以使用 lodash。

到目前为止我已经开始使用这个功能:

function CheckAllPropertiesDefined(obj){
  if (!obj) {
    return false;
  }

  for (const key in obj) {
    if (o[key] === null || o[key] === undefined) {
      return false;
    }
  }

  return true;
}

但是我正在做的事情的要求发生了变化(不再是平面 object),我意识到它不适用于嵌套属性。

运行 与此 object 的结果是正确的,但不应该是:

const obj = {
  prop1: true,
  prop2: true,
  prop3: {
    prop3a: false,
  },
  prop4: {
    test: null,
    foo: false,
    child: {
      child2: null,
    },
  },
};

它应该 return 为假,因为 prop4.testprop4.child.child2 为空。我认为一些递归是必要的。

所以 30 秒后 post 我拿出了一个绘图工具 (iPad) 并写下了解决这个问题的逻辑步骤并找到了解决方案。我强烈建议在卡住而不是 运行 互联网时这样做。

我无法在 SO 上找到适合此特定问题的解决方案,所有解决方案都仅适用于非嵌套 POJO。

如果有人可以改进它,我愿意接受。

这是我在 Javscript 中的解决方案:

function CheckAllPropertiesDefined(obj) {
  if (!obj) {
    return false;
  }

  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (typeof obj[key] === "object") {
        if (!CheckAllPropertiesDefined(obj[key])) {
          return false;
        }
      }
      if (obj[key] === null || obj[key] === undefined) {
        return false;
      }
    }
  }
  return true;
}

我通常更喜欢将对象的遍历与我们对其执行的操作分开。在这里,我将编写一个通用函数,它可以对任何(标量)节点应用谓词,并对对象或数组进行递归。然后我们可以简单地用一个测试节点不是 nullundefined 的函数来调用它,以取回用于测试对象的函数。这是一个例子:

const checkAllDeep = (pred) => (xs) =>
  Array .isArray (xs)
    ? xs .every (x => checkAllDeep (pred) (x))
  : xs && typeof xs == 'object'
    ? Object .entries (xs) .every (([k, v]) => checkAllDeep (pred) (v))
  : pred (xs)

const checkAllPropertiesDefined = checkAllDeep (x => x !== null && x !== undefined)

const obj = {prop1: true, prop2: true, prop3: {prop3a: false}, prop4: {test: null, foo: false, child: {child2: null}}}

console .log (checkAllPropertiesDefined (obj))

以后如果我们想改变谓词(例如我们想接受null而不是undefined),很容易找到。我们可以很简单地编写其他函数,例如 const allPropsAreStrings (checkAllDeep ((x) => typeof x == 'string')