从nodejs中的string调用函数

与nodejs中的window [my_func_name]等效的是什么? 我正在从stdin读取一个string,如果它是一个函数名称,我想执行它。 我认为全球[my_func_name]可能工作,但不幸的是它不。

它工作得很好

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 

不pipe这是不是一个好主意…呃,这是一个完全不同的讨论。


编辑 – ≈18个月后…是的,这是一个可怕的主意,叫这样的全球function。

这样说,你可以用更好的方式来解决这个问题。 下面我们要构build一个小的REPL (read-eval-print loop)。 为了更好地理解它,我将把它分解成几个部分。

首先,我们要确保我们的REPL在我们尝试运行他们的命令之前等待用户按下input。 要做到这一点,我们将创build一个变换stream ,在发送pipe道之前等待"\n"字符

下面的代码是使用ES6编写的。 如果您无法find兼容的环境来运行代码,我build议您查看babel 。

 // 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; 

如果你是新来的stream处理,不要在LineUnitizer上挂LineUnitizer ,这样做不太合理。 这种stream式转换是非常普遍的。 一般的想法是这样的:一旦我们将process.stdin到一个接收stream中, process.stdin就会在用户每次按下一个键时发送数据。 但是,我们的Repl (下面实现)不能在用户完成键入命令之前执行命令。 LineUnitizer是等待用户按Enter的部分(在stream中插入一个"\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 

产量

以“ >为前缀的行是用户input。 >在您的terminal中实际上不会显示。

 > 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! 

好的,这真是太棒了。 现在考虑命令可能来自任何地方。 可能是一个数据库事件,整个networking的某些事情,一个CRON工作等等。因为一切都很好地分开了,我们可以很容易地调整这个程序来轻松地接受各种input。

 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; }, 

把你的函数写在一个单独的文件中,然后将它们导出并使用名称引用来调用它们

 // 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