Java Nashorn--Part 3

jjs 的 -Scripting 选项

jjs shell 是一个不错的方法来测试一些基本的 JavaScript,或者于不太熟悉的 JavaScript包进行交互(主要是指 javax.script)的方式,然而,在即时预览功能下,它缺乏多行输入和其他先进的功能,通常会在开发中稍微受限。
相反,在非交互的情境下使用 jjs 更加合适,例如运行一个用 JavaScript 写的后台守护进程,就可以这样使用:

$ jjs -scripting my_script.js

这使我们能够利用 jjs 的增强功能,这些包括一些有用的扩展,而其中的一些扩展对熟悉脚本程序员来说更加容易。

脚本注释

在Unix脚本语言中,使用“#”来注释一行的代码,在 Nashorn 里同样适用:

#!/usr/bin/jjs
# A perfectly legal comment in scripting mode
print("After the comment");

执行内置命令

此功能通常被称为“反撇号”由经验丰富的Unix程序员来使用。所以,我们可以利用Unix curl命令用来从谷歌点击下载内容:

echo "Google says: " `curl http://www.google.co.uk

我们也可以在 Nashorn 环境下执行相同功能的 Unix 命令:

print("Google says: "+ `curl http://www.google.co.uk`);

字符串插值

字符串插值是一种特殊的语法,允许程序员直接包含一个变量而不使用字符串连接。在Nashorn中,我们可以使用语法${} 插在字符串变量。例如,上一个下载网页的例子可以用这样的插值来重写:

var url = "www.google.co.uk";
var pageContents = `curl http://${url}`;
print("Google says: ${pageContents}");

特殊变量

Nashorn 也提供了一些特殊的全局变量和函数,特别有助于脚本和正常情况下不可用的JavaScript 中。例如,一个脚本的参数可以通过变量 $ARG 来访问。这个参数用“--”来约定,像这样:

jjs test1.jjs -- aa bbb cccc

然后这些参数可以在下面的例子中访问:

print($ARG);

for(var i=0; i < $ARG.length; i++) {
    print("${i}: "+ $ARG[i]);
}

注意:
变量 $ARG 是 JavaScript 数组。对于来自其他语言的程序员(例如 Perl )来说,这个语法可能有点混乱,其中 $ 符号通常表示标量变量。

下一个特殊的全局变量,是 $ENV,提供对当前的环境变量的一个接口。例如,打印当前用户的主目录:

print("HOME = "+ $ENV.HOME); # Prints /home/ben for me

Nashorn 中也提供了一个特殊的全局函数称为 exec()。这就像我们刚才遇到的反撇号的用法,如本例所示:

var execOutput = $EXEC("echo Print this on stdout");
print(execOutput);

你可能已经注意到,当我们使用反撇号或 \(exec() 执行的命令的输出并没有打印出来,而是最终作为函数的返回值。这是为了防止在脚本的输出时打印一些无用的信息。 Nashorn 提供了其他两个特殊的变量供程序员使用,从脚本中执行命令的输出工作:\)OUT 和 $ERR,用于捕获从脚本中执行的命令的输出和任何错误消息。例如:

$EXEC("echo Print this on stdout");
// Code that doesn't change stdout
var saveOut = $OUT;
print("- - - - - - -");
print(saveOut);

内联文档

JavaScript,Java 并不支持字符串在同一个引号内分行书写,但是 Nashorn 在脚本模式下是支持的,在脚本预言中,可以使用这样的语法:<<END_TOKEN,来标识字符串的开始,一直到表示结束的标识符,这个标识符可以是任意的字符串,不过通常来使用END, END_DOC, END_STR, EOF, 和 EOSTR这样意义明显的字符串,在结束标识符结束以后,脚本语言恢复正常,看下面的例子:

var hw = "Hello World!";
var output = <<EOSTR;
This is a multiline string
It can interpolate too - ${hw}
EOSTR
print(output);

Nashorn 的辅助功能

Nashorn 还提供了一些辅助功能,让开发人员可以完成常见的任务,使执行的shell脚本更加容易:

  • print() / echo()
    我们一直在许多实例中使用 print() 方法,这些方法通常用来验证程序的预期行为。它会打印传递给它的字符串,后跟一个换行符。
  • quit() / exit()
    这两个方法完全相等,它们都会导致脚本退出。它们可以使用一个整数参数,该参数将用作脚本进程的返回代码。如果没有提供参数,按照惯例为Unix 惯例,默认使用0。
  • readLine()
    从标准输入读取一行输入(通常是键盘)。默认情况下,它将在标准输出下打印一行,但如果 readline() 返回值赋值给一个变量,输入的数据会被变量里的值替换掉,如下面的例子:
print("Please enter your name: ");
var name = readLine();
print("Please enter your age: ");
var age = readLine();
print(<<EOREC);
Student Record
-+-+-+-+-+-+-+-
Name: ${name}
Age:  ${age}
EOREC
  • readFully()
    不是从标准输入读取,readfully() 加载一个文件的所有内容。与 readline() 一样,打印内容到标准输出,或赋给一个变量:
var contents = readFully("input.txt");
  • load()
    此方法用来加载和评估(通过 JavaScript 的eval)脚本。脚本可以由本地路径或URL定位。或者,它可以使用 JavaScript 的脚本对象标识定义为一个字符串。

注意:
当使用 load() 来加载其他脚本,可能会发生意外的错误。JavaScript 支持的形式使用 try-catch 块的异常处理,那么你在加载代码应该使用它。
这里是一个简单的例子,如何从 Nashorn 负载D3可视化图形库:

try {
    load("http://d3js.org/d3.v3.min.js");
} catch (e) {
    print("Something went wrong, probably that we're not a web browser");
}
  • loadWithNewGlobal()
    当我们使用 load() 方法,它是基于当前 JavaScript 上下文脚本。有时我们想把脚本放到自己的,干净的上下文。在这些情况下,使用loadwithnewglobal() 来开始一个全新和全局的上下文。

表达式语法

这些特性使 jjs 成为一个很好的选择,就像 shell,Perl 或是其它脚本语言一样利于书写。而表达式语法这一终极特性,使得在 Nashorn 下建立书写脚本语言成为可能。

注意:
如果一个可执行的脚本的第一行以#!开头,接下来是路径的可执行文件,则 Unix 操作系统将路径指向一个解释器,能够处理这种类型的脚本。如果脚本被执行,操作系统将执行解释器并将其传递给需要处理的脚本文件。

在这种情况下,为 Nashorn 建立一个软连接会是一个非常不错的实践。我们可以吧 jjs 库的实际位置(通常是 $JAVA_HOME/bin/jjs)软连接到 /usr/bin/jjs (或 /usr/local/bin/jjs),然后脚本语言就可以这样写啦!

#!/usr/bin/jjs
# ... rest of script

对于更高级的使用情况(例如,长时间运行的守护进程),甚至可以兼容 Node.js。这是由 Avatar 项目下的 avatar.js 来实现的。
我们看到,Nashorn 使 JavaScript 代码可以直接运行在命令行工具下,但在许多情况下,我们需要在 Java 代码中执行 JavaScript,这时候我们就需要 javax.script java 这个包下的 API 了。

posted @ 2017-02-12 21:37  林本托  阅读(863)  评论(0编辑  收藏  举报