repl
是Node.js提供的一个Read-Eval-Print-Loop (REPL,读取-执行-输出-循环)实现,它即可以做为一个独立的程序使用,又可以包含在其它应用中使用。REPL是一个互式命令行解析器,它提供了一个交互式的编程环境,它可以实时的验证你所编写的代码,非常适合于验证Node.js和JavaScript的相关API。
1. REPL
模块介绍
在repl
模块中,导出了一个repl.REPLServer
。运行时,repl.REPLServer
实例会接受用户输入的各个行,并根据用户定义的评
估函数进行解析,然后输出结果。输入和输出可以是stdin
和stdout
,也可以是Node.js中的任何流。
repl.REPLServer
实例支持输入自动完成,简化的Emacs
风格,多行输入,ANSI
风格的输出,保存和恢复当前REPL
会话的状态,错误恢复以及可定制的评价功能。
1.1 命令与特殊的键
以下几个特殊的指令可以在所有REPL实例中使用:
.break
- 当处理多行表达式输入时,输入.break
命令(或输入<ctrl>-C
)将中止之后的输入或表达式处理。.clear
- 重置 REPL的context
为一个空对象,并清空当前任何多行输入表达式。.exit
- 关闭 I/O 流,会造成 REPL 退出.help
- 显示命令列表.save
- 将当前 REPL 会话保存到一个文件:> .save ./file/to/save.js
.load
- 加载一个文件到当前 REPL 会话:> .load ./file/to/load.js
.editor
- 进入编辑模式 (<ctrl>-D
完成编辑,<ctrl>-C
取水编辑)
> .editor // Entering editor mode (^D to finish, ^C to cancel) function welcome(name) { return `Hello ${name}!`; } welcome('Node.js User'); // ^D 'Hello Node.js User!' >
在REPL中,可以使用以下特殊键:
<ctrl>-C
- 按下一次时,结果与.break
命令相同。在一个空白行中按下两次时,结果与.exit
命令相同<ctrl>-D
- 与.exit
命令相同<tab>
- 在空白行中按下时,列出全局与本地变量。在进行输入时按下时,显示相关自动完成选项。
1.2 默认解析
默认情况下,所有repl.REPLServer
实例会使用一个默认解析函数,对JavaScript表达式或Node.js内置模块进行解析。但这种默认行为,可以在创建repl.REPLServer
时指定一个解析函数进行替换。
JavaScript表达式
默认编译器支持对JavaScript表达式的直接解析:
> 1 + 1 2 > var m = 2 undefined > m + 1 3
除非是使用了语句块(如:{…}
)或函数,或在全局作用域中声明的变量或使用该无功关键字关键字声明的变量。
全局与本地作用域
默认情况下,可以在全局范围内访问任何存在的变量。例如:
const repl = require('repl'); var msg = 'message'; repl.start('> ').context.m = msg;
context
对象的属性可以在REPL本地出现:
$ node repl_test.js > m 'message'
访问Node.js核心模块
默认情况下,解析器会在使用时自动加载Node.js核心模块。除非另外声明全局或局部变量,输入fs
时会解析global.fs = require('fs')
:
> fs.createReadStream('./some/file');
赋值下划线(_
)变量
默认解析器,在默认情况下会通过一个特殊的变量_
来指定解析表达式:
> [ 'a', 'b', 'c' ] [ 'a', 'b', 'c' ] > _.length 3 > _ += 1 4
当显式的为_
设置值时,会改变这种默认方式。
1.3 自定义解析函数
创建一个新的repl.REPLServer
实例后,可能会传入一个自定义的解析函数。
以下是一个用于语言转换的说明示例:
const repl = require('repl'); const Translator = require('translator').Translator; const myTranslator = new Translator('en', 'fr'); function myEval(cmd, context, filename, callback) { callback(null, myTranslator.translate(cmd)); } repl.start({prompt: '> ', eval: myEval});
1.4 自定义REPL输出
默认情况下,repl.REPLServer
实例会在向所提示的可写流(默为process.stdout
)写入输出前,使用util.inspect()方法进行格式化。可以向writer
参数传入一个函数对repl.REPLServer
实例进行完全自定义输出:
const repl = require('repl'); const r = repl.start({prompt: '>', eval: myEval, writer: myWriter}); function myEval(cmd, context, filename, callback) { callback(null,cmd); } function myWriter(output) { return output.toUpperCase(); }
2. 类:REPLServer
添加于v0.1.91
repl.REPLServer
类继承自readline.Interface类。repl.REPLServer
实例通过repl.start()
方法创建,且不能显示的使用new
关键字创建。
2.1 repl.REPLServer
对象事件
Event: 'exit'
添加于v0.7.7
'exit'
事件会在REPL退出或是输入.exit
命令后发送,用户按两次<ctrl>-C
发送SIGINT
信号,或是按<ctrl>-D
向输入流发送'end'
信号。被调用的监听函数没有任何参数:
replServer.on('exit', () => { console.log('Received "exit" event from repl!'); process.exit(); });
Event: 'reset'
添加于v0.11.0
'reset'
事件会在REPL的内容被重置时发送。无论是否收到.clear
命令都会发生,除非REPL使用默认的解析器且repl.REPLServer
创建实例时将useGlobal
选项设置为true
。其回调函数中仅有一个context
参数:
const repl = require('repl'); function initializeContext(context) { context.m = 'test'; } var r = repl.start({prompt: '>'}); initializeContext(r.context); r.on('reset', initializeContext);
以上代码执行时,全局的'm'
变量可以被修改但使用.clear
命令时会被重置为初始值:
$ ./node example.js >m 'test' >m = 1 1 >m 1 >.clear Clearing context... >m 'test' >
2.2 repl.REPLServer
对象方法
replServer.defineCommand(keyword, cmd)
- 定义命令
添加于v0.3.0
keyword
<String> 命令关键字 (无.
前缀)cmd
<Object> | <Function> 被命令调用的处理函数
replServer.displayPrompt()
方法用于向REPL添加新的以.
为前缀的命令。这样输入命令时,首先输入.
其次是关键字。cmd
可以是一个函数,或是一个包含以下参数的对象:
help
<String> 被.help
命令所显示的帮助信息 (可选)。action
<Function> 要执行的函数
如,向REPL实例添加两个新命令:
const repl = require('repl'); var replServer = repl.start({prompt: '> '}); replServer.defineCommand('sayhello', { help: 'Say hello', action: function(name) { this.lineParser.reset(); this.bufferedCommand = ''; console.log(`Hello, ${name}!`); this.displayPrompt(); } }); replServer.defineCommand('saybye', function() { console.log('Goodbye!'); this.close(); });
定义后可以在命令行中像下面这样调用:
> .sayhello Node.js User Hello, Node.js User! > .saybye Goodbye!
replServer.displayPrompt([preserveCursor])
- 显示提示
添加于v0.1.91
preserveCursor
<Boolean>
replServer.displayPrompt()
方法会为REPL实例准备用户输入,并在一个新行打印提示信息。
当preserveCursor
为true
时,光标不会放在0
的位置。
3. repl.start([options])
- 创建实例
repl.start()
是一个用于使用REPL实例的工厂方法。options
参数是一个可包含以下参数的对象:
prompt
<String> 要显示的输入提示。默认为>
input
<Readable> REPL要读取的输入流。默认为process.stdin
output
<Writable> REPL要写入的输出流。默认为process.stdout
terminal
<boolean> 如果为true
,指定的output
需要做为一个TTY终端处理。eval
<Function> 对每个输入行进行解析时所执行的函数。默认为eval()
。useColors
<boolean> 如果为true
,指定的writer
函数需要包括 ANSI 颜色风格替代输出。如果自定义writer
函数,这会没有效果。默认为 REPL 实例的terminal
值useGlobal
<boolean> 如果为true
,指定的默认解析函数会使用JavaScriptglobal
上下文为实例创建新的独立内容。默认为false
ignoreUndefined
<boolean> 如果为true
,指定的默认写入,在评价为undefined
时将不会返回一个值。默认为false
.writer
<Function> 在向output
写入数据时,调用的格式化函数。默认为util.inspect()
completer
<Function> 用于自定义Tab自动完成的可选函数。参见readline.InterfaceCompleter
replMode
- 指定所有的 JavaScript 命令的运行模式,可以是严格模式、默认模式、或hybrid
模式(code
模式)。可选值有:repl.REPL_MODE_SLOPPY
- 在松散模式下执行repl.REPL_MODE_STRICT
- 在严格模式下执行repl.REPL_MODE_MAGIC
- 在默认模式下执行
breakEvalOnSigint
- 当收到SIGINT
信号后,停止当前解析。如,按下Ctrl+C
时。这不能用于自定义的eval
函数。默认为false