Javascript递归嵌套比较循环

时间:2018-06-01 00:35:14

标签: javascript loops object recursion lodash

我正在尝试创建一个循环遍历配置对象的递归函数,该对象包含必须设置的密钥,稍后将其与appConfig进行比较,它必须匹配内部的所有密钥(嵌套) unsetConfig

const _ = window._
const UNSET_CONFIG_VAR = 'UNSET'

let config = {
  logging: {
    hasConsole: UNSET_CONFIG_VAR,
    hasSyslog: UNSET_CONFIG_VAR,
    processName: UNSET_CONFIG_VAR,
    inner: {
      test: UNSET_CONFIG_VAR
    }
  }
}

const unsetConfig = _.clone(config)

function initialize (appConfig) {
  const walkConfig = (currentConfigLevel, previousPaths = []) => {
    for (const [key, value] of Object.entries(currentConfigLevel)) {
      if (_.isObject(value)) {
        previousPaths.push(key)
        walkConfig(currentConfigLevel[key], previousPaths)
      }

      const path = previousPaths.length !== 0 ? previousPaths.join('.') : key

      if (!_.get(appConfig, path)) {
        throw new Error(`Config was missing: ${path}`)
      }
    }
  }

  walkConfig(unsetConfig)
}

initialize({
  logging: {
    hasConsole: true,
    hasSyslog: true,
    processName: true,
    inner: {
      as: true
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>

预期输出将会引发错误,因为您可以在initialize函数中看到test中缺少logging.inner密钥。

但不会抛出任何错误。

我现在尝试了不同的设置,但我有点坚持这个。

1 个答案:

答案 0 :(得分:2)

如果您只想检查特定路径中是​​否存在值,则只需使用lodash#has。使用lodash#get将从特定路径获取特定属性的值,但使用此值检查此类路径的存在是不可靠的,因为该值可能是一个虚假值。

此外,lodash#haslodash#get接受的路径参数接受字符串或数组,因此您实际上不需要从分隔符连接它们。事实上,当你的一个配置属性包含一个数组时,以这种方式加入它会失败。由于阵列密钥符号被包在一个括号中,例如[0][1]

function initialize(appConfig) {

  const walkConfig = (config, paths = []) => {
    Object.entries(config).forEach(([key, value]) => {
      let $paths = paths.concat(key);

      if(!_.has(appConfig, $paths)) {
        throw new Error(`Config was missing: ${$paths.join('.')}`);
      }

      if(_.isObject(value)) {
        walkConfig(value, $paths);
      }
    });
  };

  walkConfig(unsetConfig);

}

const { _ } = window;
const UNSET_CONFIG_VAR = 'UNSET'

let config = {
  logging: {
    hasConsole: UNSET_CONFIG_VAR,
    hasSyslog: UNSET_CONFIG_VAR,
    processName: UNSET_CONFIG_VAR,
    inner: {
      test: UNSET_CONFIG_VAR
    }
  }
}

const unsetConfig = _.cloneDeep(config); // Clone inner objects as well

function initialize(appConfig) {
  
  const walkConfig = (config, paths = []) => {
    Object.entries(config).forEach(([key, value]) => {
      let $paths = paths.concat(key);
      
      if(!_.has(appConfig, $paths)) {
        throw new Error(`Config was missing: ${$paths.join('.')}`);
      }
      
      if(_.isObject(value)) {
        walkConfig(value, $paths);
      }
    });
  };
  
  walkConfig(unsetConfig);
  
}

initialize({
  logging: {
    hasConsole: false,
    hasSyslog: true,
    processName: true,
    inner: {
      as: true
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>