我想知道如何在一个代码块内进行对象的破坏性赋值,但接收的变量在模块作用域,而不是在代码运行的块内,而不必在多个作用域重复定义?
我很高兴地在我的模块的顶层作用域使用这样的对象破坏赋值,它创建了一堆顶层模块范围的变量,这就是我的代码所期望的。
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);
}
由于模块中的其他函数依赖于选项值,我认为只有在主导出函数中定义了选项值后才初始化这些函数是最合理的。这样做还有一个好处,就是避免了作为主函数的副作用的重新赋值,这会使代码更难理解和测试)。走这条路,你可以一次性把参数值放到变量中,同时也可以重命名属性,还可以设置它们的默认值,我认为这是你需要的关键见解。
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' });
如果变量必须在顶层定义,那么就无法避免重复这些变量了 至少两次 - 一次在顶层声明,一次可能在导出的函数中重新分配。你可以将3-repetitions变成2-repetitions,通过在 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();
}
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' });
你可以将两件事结合起来使用。Object.assign()
和解构可以通过。
function init() {
let obj = {prop1, prop2} = getValues();
Object.assign(globalThis, obj);
}