如何对更高范围的变量集进行解构赋值?

How to do destructuring assignment to a higher scoped set of variables?

我试图找出如何从代码块内进行对象解构赋值,但是接收变量位于模块范围内,而不是代码 运行s 没有的块内在多个范围内重复定义?

我很高兴在我的模块的顶级范围内使用这样的对象解构赋值,它创建了一堆顶级模块范围的变量,这是我的代码所期望的:

let {
    numToRead,
    numConcurrent,
    numWorkers,
    skipParsing,
    preOpenFiles,
    dir: sourceDir,
    binary: doBinary,
} = processArgs(spec);

当我的模块 运行 作为顶级模块并直接从命令行读取其参数时执行此代码(processArgs() 解析命令行)。但是,现在我需要更改代码,以便此代码 运行 有条件地(它在 if 块内)并且有时参数通过导出函数中的选项对象传入。

所以,我开始写这个:

// if executed directly from the command line, get options from the command line
if (require.main === module) {

    // module level configuration variables from command line arguments (with defaults)
    let {
        numToRead,
        numConcurrent,
        numWorkers,
        skipParsing,
        preOpenFiles,
        dir: sourceDir,
        binary: doBinary,
    } = processArgs(spec);

    // more code here
}

module.exports = function(options) {
    // run this from options passed in by another module, rather than the command line
    // this code also needs to populate the same top level module variables
}

但是,这个 if 块在块范围内创建了所有这些变量,这不是我需要的。我需要它们位于模块的顶层。

当解构赋值在一个块内时,有没有办法让这些变量在模块的顶层自动创建,而不必重复所有顶层变量的定义?


我能够让它工作的唯一方法是三个单独的命名顶级变量列表,这似乎是我想避免的不好的做法。这些是否可以避免并且仍然以顶级变量结束:

// top level module arguments
let numToRead = 0,
    numConcurrent = 4,
    numWorkers = 5,
    skipParsing = false,
    preOpenFiles = "false",
    sourceDir = "./buckets",
    doBinary = false;

function run(options) {
    // load arguments into top level module variables
    ({
        numToRead,
        numConcurrent,
        numWorkers,
        skipParsing,
        preOpenFiles,
        dir: sourceDir,
        binary: doBinary,
    } = options);

    analyzeWithWorkers().catch(err => {
        console.log(err);
        process.exit(1);
    });
}

// for running from the command line
if (require.main === module) {
    run(processArgs(spec));
}

// for calling this from another module
module.exports = function(options) {
    // have to fill in any missing arguments
    // here as all options are optional
    let fullOptions = Object.assign({
        numToRead,
        numConcurrent,
        numWorkers,
        skipParsing,
        preOpenFiles,
        dir: sourceDir,
        binary: doBinary}, options);
    run(fullOptions);
}

你可以结合使用两个东西。 Object.assign() 解构可以通过

function init() {
      let obj = {prop1, prop2} = getValues();
      Object.assign(globalThis, obj);
}

由于模块中的其他函数依赖于选项值,我认为只有在主导出函数中定义了选项值后才初始化这些函数才最有意义。 (这也有一个好处,即避免将重新分配作为 main 函数的副作用,这会使代码更难理解和测试。)走这条路,您可以立即将参数值放入变量中,同时还可以重命名属性,并设置它们的默认值,我认为这是您需要的关键洞察力:

function main(options) {
  const {
    numToRead = 0,
    numConcurrent = 4,
    numWorkers = 5,
    skipParsing = false,
    preOpenFiles = "false",
    dir: sourceDir = "./buckets",
    binary: doBinary = false
  } = options;
  function analyzeWithWorkers() {
    // reference variables here
    // ...
  }
  // initialize other functions if needed, referencing those variables
  analyzeWithWorkers().catch(err => {
      console.log(err);
      process.exit(1);
  });
}
if (require.main === module) {
  main(processArgs(spec));
}
module.exports = main;

function main(options) {
  const {
    numToRead = 0,
    numConcurrent = 4,
    numWorkers = 5,
    skipParsing = false,
    preOpenFiles = "false",
    dir: sourceDir = "./buckets",
    binary: doBinary = false
  } = options;
  function analyzeWithWorkers() {
    console.log(skipParsing, sourceDir);
    return Promise.resolve();
  }
  // initialize other functions if needed, referencing those variables
  analyzeWithWorkers().catch(err => {
      console.log(err);
      process.exit(1);
  });
}
/*
if (require.main === module) {
  main(processArgs(spec));
}
module.exports = main;
*/
main({});
main({ dir: 'someDir' });

如果必须在顶层定义变量,则没有办法将它们全部重复 至少两次 - 一次在顶层声明,一次可能在导出的函数中重新分配。您可以通过在 run 内分配默认值将您的 3 次重复变成 2 次重复,导出函数分配给外部变量(假设模块总是由命令行或主程序从外部调用导出函数)。

let numToRead,
    numConcurrent,
    numWorkers,
    skipParsing,
    preOpenFiles,
    sourceDir,
    doBinary;

function run(options) {
    // load arguments into top level module variables
    ({
        numToRead = 0,
        numConcurrent = 4,
        numWorkers = 5,
        skipParsing = false,
        preOpenFiles = "false",
        dir: sourceDir = "./buckets",
        binary: doBinary = false
    } = options);
    analyzeWithWorkers().catch(err => {
        console.log(err);
        process.exit(1);
    });
}

function analyzeWithWorkers() {
    console.log(skipParsing, sourceDir);
    return Promise.resolve();
}
if (require.main === module) {
  run(processArgs(spec));
}
module.exports = run;

let numToRead,
    numConcurrent,
    numWorkers,
    skipParsing,
    preOpenFiles,
    sourceDir,
    doBinary;
    
function run(options) {
    // load arguments into top level module variables
    ({
        numToRead = 0,
        numConcurrent = 4,
        numWorkers = 5,
        skipParsing = false,
        preOpenFiles = "false",
        dir: sourceDir = "./buckets",
        binary: doBinary = false
    } = options);
    analyzeWithWorkers().catch(err => {
        console.log(err);
        process.exit(1);
    });
}

function analyzeWithWorkers() {
    console.log(skipParsing, sourceDir);
    return Promise.resolve();
}
run({});
run({ dir: 'someDir' });