-1

我正在尝试创建一个循环遍历配置对象的递归函数,该对象包含必须设置的键,这与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.

但不会抛出任何错误。

我现在已经在不同的设置中尝试过,但我有点坚持。

4

1 回答 1

2

如果您只想检查某个路径中的值是否存在,那么您只需要使用lodash#has. usinglodash#get将从某个路径获取特定属性的值,但是使用该值来检查该路径的存在是不可靠的,因为该值可能是假值。

此外,两者都接受 path 参数lodash#haslodash#get接受字符串或数组,因此您实际上不需要从分隔符连接它们。实际上,当您的配置属性之一包含数组时,以这种方式加入它会失败。由于数组键符号包含在括号中,例如[0]or [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>

于 2018-06-01T01:13:47.377 回答