从Node.js中的字符串调用函数 [英] Call function from string in nodejs

查看:160
本文介绍了从Node.js中的字符串调用函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

nodejs中的window [my_func_name]等效于什么?我正在从stdin读取一个字符串,如果它是一个函数名,我想执行它.我以为global [my_func_name]可能有用,但不幸的是,它无效.

What is the equivalent to window[my_func_name] in nodejs? I'm reading a string from stdin and if it's a function name I want to execute it. I thought global[my_func_name] might work but unfortunately it doesn't.

推荐答案

效果很好

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

这是否是个好主意... 那是完全不同的讨论.

Whether or not this is a good idea... well, that's an entirely different discussion.

编辑—大约18个月后...是的,调用这样的全局函数是一个可怕的想法.

EDIT — ≈18 months later... Yeah, it's a horrible idea to call a global function like that.

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

In saying that, here's one way you could approach the problem in a much better way. Below we're going to build a little REPL (read-eval-print loop). In order to understand it better, I'll break it down into a couple parts.

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

First, we want to make sure our REPL waits for the user to press enter before we try running their command. To do that, we'll create a transform stream that waits for a "\n" character before sending a line down the pipe

以下代码是使用 ES6 编写的.如果您找不到兼容的环境来运行代码,建议您查看 babel .

The code below is written using ES6. If you're having trouble finding a compatible environment to run the code, I suggest you check out 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;

如果您不是流处理的新手,请不要挂在 LineUnitizer 上,这没有任何意义.这种流转换非常普遍.总体思路是这样的:一旦将 process.stdin 用管道传输到接收流中,则每次用户按下键时, process.stdin 就会发出数据.但是,直到用户完成键入命令后,我们的 Repl (以下实现)才能对命令执行操作. LineUnitizer 是等待用户按下Enter键(将"\ n" 插入流中)然后发出信号通知 _transform 的部分.该命令已准备好发送到 repl 进行处理!

Don't get too hung up on LineUnitizer if you're new to stream processing and it doesn't quite make sense. This kind of stream transform is extremely common. The general idea is this: once we pipe process.stdin into a receiving stream, process.stdin will be emitting data every time the user presses a key. However, our Repl (implemented below) can't act on a command until the user has finished typing the command. LineUnitizer is the part that waits for the user to press enter (which inserts a "\n" into the stream) and then signals to _transform that the command is ready to be sent to repl for processing!

现在让我们看看 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 接收到一行时,它都会发出带有一些args的事件.这是查看命令解析方式的直观方式

Well hey, that was easy! What does it do tho? Each time repl receives a line, it emits an event with some args. Here's a visual way to see how a command is parsed

The user enters       emit event      args
-------------------------------------------------------------
add 1 2 3             "add"           ["1", "2", "3"]
hens chocobo cucco    "hens"          ["chocobo", "cucco"]
yay                   "yay"           []

好吧,现在让我们将所有内容连接在一起以查看其工作原理

Ok, now let's wire everything together to see it work

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

输出

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

Lines prefixed with > are user input. The > will not actually be visible in your 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!


如果您认为这很棒,那么我们甚至还没有完成.这样编写程序的好处是,无论命令如何到达我们的程序,我们都可以对其执行操作.


If you think that's awesome, we're not even done yet. The benefits of writing our program this way is that we can act on the commands regardless of how they arrive at our program.

考虑此 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作业等.由于所有内容都很好地分开了,因此我们可以轻松地使此程序适应于轻松接受各种输入的过程.


Ok, so that's pretty fricken great. Now consider that the commands could come from anywhere. Could be a database event, something across the network, a CRON job, etc. Because everything is nicely separated, we could easily adapt this program to accept a variety of inputs with ease.

这篇关于从Node.js中的字符串调用函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆