从nodejs中的字符串调用函数

Pau*_*ulK 5 string global window function node.js

与nodejs中的window [my_func_name]相同的是什么?我正在从stdin读取一个字符串,如果它是一个函数名,我想执行它.我认为全局[my_func_name]可能有效,但不幸的是它没有.

Tha*_*you 12

它工作得很好

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();
Run Code Online (Sandbox Code Playgroud)

产量

foo
foo was called
bar
could not find bar function
Run Code Online (Sandbox Code Playgroud)

这是否是一个好主意......嗯,这是一个完全不同的讨论.


编辑 - ≈18个月后......是的,调用像这样的全局函数是一个可怕的想法.

在说,这是一种可以更好地解决问题的方法.下面我们将构建一个小的REPL(read-eval-print循环).为了更好地理解它,我将其分解为几个部分.

首先,我们要确保我们的REPL在尝试运行命令之前等待用户按Enter键.为此,我们将创建一个转换流,"\n"在发送line管道之前等待一个字符

下面的代码是使用ES6编写的.如果您在查找兼容环境以运行代码时遇到问题,我建议您查看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;
Run Code Online (Sandbox Code Playgroud)

LineUnitizer如果您不熟悉流处理,请不要过于依赖它,并且它没有多大意义.这种流变换非常普遍.一般的想法是这样的:一旦我们管道process.stdin接收流,process.stdin每次用户按下一个键就会发出数据.但是,Repl在用户完成键入命令之前,我们(在下面实现)无法对命令执行操作.LineUnitizer是等待用户按Enter键(将其插入"\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;
Run Code Online (Sandbox Code Playgroud)

嘿,这很容易!它是做什么的?每次repl收到一行时,它会发出一个带有一些args的事件.这是一种可视方式,用于查看命令的解析方式

The user enters       emit event      args
-------------------------------------------------------------
add 1 2 3             "add"           ["1", "2", "3"]
hens chocobo cucco    "hens"          ["chocobo", "cucco"]
yay                   "yay"           []
Run Code Online (Sandbox Code Playgroud)

好的,现在让我们将所有内容连接在一起,看它是否有效

// 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();
      }));
Run Code Online (Sandbox Code Playgroud)

运行

$ node start.js
Run Code Online (Sandbox Code Playgroud)

产量

前缀的行>是用户输入.该>不会实际上是在终端显示.

> add 1 2 3
add result: 6
> shout I can see it in your face!
I CAN SEE IT IN YOUR FACE!
> exit
kthxbai!
Run Code Online (Sandbox Code Playgroud)

如果你认为这很棒,我们甚至还没有完成.以这种方式编写程序的好处是,无论他们如何到达我们的程序,我们都可以对命令采取行动.

考虑这个commands.txt文件

add 100 200
shout streams are the bee's knees
exit
Run Code Online (Sandbox Code Playgroud)

现在像这样运行它

$ cat commands.txt | node start.js
Run Code Online (Sandbox Code Playgroud)

产量

300
STREAMS ARE THE BEE'S KNEES
kthxbai!
Run Code Online (Sandbox Code Playgroud)

好的,所以这很棒.现在考虑命令可以来自任何地方.可能是一个数据库事件,网络上的东西,CRON工作等等.因为一切都很好地分开,我们可以轻松地调整这个程序,轻松接受各种输入.


小智 11

在单独的文件中编写您的函数并导出它们并使用该名称引用来调用它们,例如

//    functions.js
var funcOne = function(){
                   console.log('function ONE called')
              }
module.exports={
    //  name_exported : internal_name
    funcOne : funcOne
}
Run Code Online (Sandbox Code Playgroud)

在 index.js 中使用 functions.js 中定义的函数

//    index.js
var methods = require('./functions.js')   // path to functions.js
methods['funcOne']()
Run Code Online (Sandbox Code Playgroud)

输出 :

> node index.js
> function ONE called
Run Code Online (Sandbox Code Playgroud)