nodejs中的window[my_func_name]等价于什么?我正在从标准输入读取一个字符串,如果它是一个函数名,我想执行它。我认为 global[my_func_name] 可能有效,但不幸的是它没有。
4 回答
它工作得很好
global.foo = function foo () {
console.log("foo was called");
}
process.stdin.on("data", function(input) {
// don't forget to call .trim() to remove the \n
var fn = input.toString().trim();
// function exists
if (fn in global && typeof global[fn] === "function") {
global[fn]();
}
// function does not exist
else {
console.log("could not find " + fn + " function");
}
});
process.stdin.resume();
输出
foo
foo was called
bar
could not find bar function
这是否是一个好主意……嗯,这是一个完全不同的讨论。
编辑——大约 18 个月后......是的,调用这样的全局函数是一个可怕的想法。
话虽如此,这是一种可以更好地解决问题的方法。下面我们将构建一个小的REPL(读取-评估-打印循环)。为了更好地理解它,我将把它分成几个部分。
首先,我们要确保我们的 REPL 在尝试运行他们的命令之前等待用户按 Enter。为此,我们将创建一个转换流"\n"
,它在发送一个字符之前等待一个line
字符
// line-unitizer.js
import {Transform} from 'stream';
class LineUnitizer extends Transform {
constructor(delimiter="\n") {
super();
this.buffer = "";
this.delimiter = delimiter;
}
_transform(chunk, enc, done) {
this.buffer += chunk.toString();
var lines = this.buffer.split(this.delimiter);
this.buffer = lines.pop();
lines.forEach(line => this.push(line));
done();
}
}
export default LineUnitizer;
如果您不熟悉流处理,请不要太纠结LineUnitizer
,这不太有意义。这种流变换极为常见。总体思路是这样的:一旦我们通过管道process.stdin
进入接收流,process.stdin
每次用户按键时都会发出数据。但是,我们的Repl
(在下面实现)在用户完成输入命令之前不能对命令进行操作。LineUnitizer
是等待用户按 Enter 键(将 a"\n"
插入流中)然后发出信号通知_transform
该命令已准备好发送到repl
处理的部分!
Repl
现在让我们看看
// repl.js
import {Writable} from 'stream';
class Repl extends Writable {
_parse(line) {
var [cmd, ...args] = line.split(/\s+/);
return {cmd, args};
}
_write(line, enc, done) {
var {cmd, args} = this._parse(line.toString());
this.emit(cmd, args);
done();
}
}
export default Repl;
好吧,这很容易!它有什么作用?每次repl
收到一行,它都会发出一个带有一些参数的事件。这是查看如何解析命令的直观方式
The user enters emit event args
-------------------------------------------------------------
add 1 2 3 "add" ["1", "2", "3"]
hens chocobo cucco "hens" ["chocobo", "cucco"]
yay "yay" []
好的,现在让我们将所有东西连接在一起以查看它的工作原理
// start.js
import LineUnitizer from './line-unitizer';
import Repl from './repl';
process.stdin
.pipe(new LineUnitizer())
.pipe(
(new Repl())
.on("add", function(args) {
var sum = args.map(Number).reduce((a,b) => a+b, 0);
console.log("add result: %d", sum);
})
.on("shout", function(args) {
var allcaps = args.map(s => s.toUpperCase()).join(" ");
console.log(allcaps);
})
.on("exit", function(args) {
console.log("kthxbai!");
process.exit();
}));
运行
$ node start.js
输出
带有前缀的行
>
是用户输入。在您的>
终端中实际上不会看到。
> add 1 2 3
add result: 6
> shout I can see it in your face!
I CAN SEE IT IN YOUR FACE!
> exit
kthxbai!
如果您认为这很棒,我们甚至还没有完成。以这种方式编写程序的好处是我们可以对命令采取行动,而不管它们如何到达我们的程序。
考虑这个commands.txt
文件
add 100 200
shout streams are the bee's knees
exit
现在像这样运行它
$ cat commands.txt | node start.js
输出
300
STREAMS ARE THE BEE'S KNEES
kthxbai!
好的,那真是太棒了。现在考虑命令可能来自任何地方。可以是数据库事件、网络上的某些事情、CRON 作业等。因为一切都很好地分开,我们可以轻松地调整这个程序以轻松接受各种输入。
将你的函数写在一个单独的文件中并导出它们并使用它的名称引用来调用它们,比如
// functions.js
var funcOne = function(){
console.log('function ONE called')
}
module.exports={
// name_exported : internal_name
funcOne : funcOne
}
在 index.js中使用 functions.js 中定义的函数:
// index.js
var methods = require('./functions.js') // path to functions.js
methods['funcOne']()
输出 :
> node index.js
> function ONE called
var theTests = require('./tests');
//@TODO CaseID should be caseId
var CaseID = 5678;
// use dynamic functions
var functionName = 'theTests.TEST_' + CaseID;
var functionString = String('TEST_' + CaseID);
var check = eval( 'typeof ' + functionName ); // bad
if ( check == 'function' ) {
// run the function
// testResult = eval( functionName ); nope
testResult = theTests[functionString](); //yep :)
console.log(testResult);
}
else {
console.log( 'No test functions for ' + CaseID );
}
在这个示例中,tests.js 将寻找...
TEST_5678: function(){
return some thing;
},
我自己也遇到了同样的问题,我也是一个新手,所以带着一点盐 - 从这里的其他帖子中提到这个global
对象,我还发现这module
似乎是 Node.js 中的本地对象,在其exports
上定义。
所以如果你有一个模块:
exports.myFunction = myFunction;
在某些时候,在你声明了导出之后(你可以在文件/脚本的顶部写你的导出,甚至在你声明 myFunction() 之前),你调用:
module.exports['myFunction']()
这基本上会调用myFunction()
再一次,新手,所以请带上一粒盐。