ナショーン入門
1前書き
この記事は、Java 8以降のJVMの新しいデフォルトJavaScriptエンジンである__Nashornに焦点を当てています。
多くの洗練されたテクニックがその前身の
Rhinoと比べて
Nashorn__桁の性能を上げるために使われてきたので、それは価値のある変更です。
それが使用されることができる方法のいくつかを見てみましょう。
2コマンドライン
JDK 1.8には、
jjs
というコマンドラインインタプリタが含まれています。これは、JavaScriptファイルを実行するため、または引数なしで起動した場合はREPL(対話型シェル)として使用できます。
$ $JAVA__HOME/bin/jjs hello.js
Hello World
ここで、ファイル
hello.js
には、単一の命令が含まれています。
print(“ Hello World”);
同じコードを対話的に実行することができます。
$ $JAVA__HOME/bin/jjs
jjs> print("Hello World")
Hello World
最初の行に
#!$ JAVA
HOME/bin/jjs
を追加して、ターゲットスクリプトを実行するために
jjs__を使用するように** nixランタイムに指示することもできます。
#!$JAVA__HOME/bin/jjs
var greeting = "Hello World";
print(greeting);
そしてファイルは通常通りに実行することができます。
$ ./hello.js
Hello World
3埋め込みスクリプトエンジン
JVM内からJavaScriptを実行する2番目の、そしておそらくもっと一般的な方法は__ScriptEngineを使うことです。 JVMの実装、もちろん)。
JavaScript ____エンジンを作成しましょう。
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
Object result = engine.eval(
"var greeting='hello world';" +
"print(greeting);" +
"greeting");
ここでは新しい
ScriptEngineManager
を作成し、すぐにそれに
nashorn
という名前の
ScriptEngine
を渡すように依頼します。それから、いくつかの命令を渡して、予想どおり
String
“
hello world
“であることが判明した結果を取得します。
4スクリプトにデータを渡す
Bindings
オブジェクトを定義し、それを2番目のパラメーターとして
eval
関数に渡すことで、データをエンジンに渡すことができます。
Bindings bindings = engine.createBindings();
bindings.put("count", 3);
bindings.put("name", "baeldung");
String script = "var greeting='Hello ';" +
"for(var i=count;i>0;i--) { " +
"greeting+=name + ' '" +
"}" +
"greeting";
Object bindingsResult = engine.eval(script, bindings);
このスニペットを実行すると、「
こんにちはbaeldung baeldung baeldung
」となります。
5 JavaScript関数を呼び出す
もちろん、あなたのJavaコードからJavaScriptの関数を呼び出すことも可能です。
engine.eval("function composeGreeting(name) {" +
"return 'Hello ' + name" +
"}");
Invocable invocable = (Invocable) engine;
Object funcResult = invocable.invokeFunction("composeGreeting", "baeldung");
これは“
Hello baeldung
”を返します。
6. Javaオブジェクトの使い方
我々はJVM内で実行しているので、JavaScriptコード内からネイティブJavaオブジェクトを使用することが可能です。
これは
Java
オブジェクトを使用して実現されます。
Object map = engine.eval("var HashMap = Java.type('java.util.HashMap');" +
"var map = new HashMap();" +
"map.put('hello', 'world');" +
"map");
7. 言語拡張機能
-
Nashorn
はECMAScript 5.1 ** をターゲットとしていますが、JavaScriptの使用を少し良くするための拡張機能を提供します。
7.1. for-each
を使用してコレクションを繰り返す
For-each
は、さまざまなコレクションの反復処理を簡単にするための便利な拡張機能です。
String script = "var list =[1, 2, 3, 4, 5];" +
"var result = '';" +
"for each (var i in list) {" +
"result+=i+'-';" +
"};" +
"print(result);";
engine.eval(script);
ここでは、forfor each__ iteration構文を使用して配列の要素を結合します。
結果の出力は
1-2-3-4-5-
になります。
7.2. 関数リテラル
単純な関数宣言では、中括弧を省略することができます。
function increment(in) ++in
明らかに、これは単純なワンライナー関数に対してのみ行うことができます。
7.3. 条件付きキャッチ句
指定した条件が真の場合にのみ実行される、保護されたcatch句を追加することができます。
try {
throw "BOOM";
} catch(e if typeof e === 'string') {
print("String thrown: " + e);
} catch(e) {
print("this shouldn't happen!");
}
これにより、「
String thrown:BOOM
」と表示されます。
7.4. 型付き配列と型変換
Java型の配列を使用したり、JavaScriptの配列との間で変換したりすることができます。
function arrays(arr) {
var javaIntArray = Java.to(arr, "int[]");
print(javaIntArray[0]);
print(javaIntArray[1]);
print(javaIntArray[2]);
}
Nashorn
は、動的に型指定されたJavaScript配列のすべての値が整数のみのJava配列に収まるように、ここでいくつかの型変換を実行します。
引数
[100、“ 1654”、true]
を指定して上記の関数を呼び出した結果、100、1654、および1(すべての数値)が出力されます。
String
とブール値は、暗黙のうちに論理整数値に変換されました。
7.5.
Object.setPrototypeOf
を使用してオブジェクトのプロトタイプを設定する
Nashorn
は、オブジェクトのプロトタイプを変更できるようにするAPI拡張を定義します。
Object.setPrototypeOf(obj, newProto)
この関数は一般的に
Object.prototype .
proto
____に代わるより良い代替手段と考えられているので、すべての新しいコードでオブジェクトのプロトタイプを設定するのが好ましい方法です。
7.6. 魔法
_noSuchProperty
と
_ noSuchMethod
undefined
プロパティがアクセスされたとき、または
undefined
メソッドが呼び出されたときに必ず呼び出されるメソッドをオブジェクトに定義することができます。
var demo = {
____noSuchProperty____: function (propName) {
print("Accessed non-existing property: " + propName);
},
____noSuchMethod____: function (methodName) {
print("Invoked non-existing method: " + methodName);
}
};
demo.doesNotExist;
demo.callNonExistingMethod()
これは印刷されます:
Accessed non-existing property: doesNotExist
Invoked non-existing method: callNonExistingMethod
7.7. オブジェクトプロパティを
Object.bindProperties
でバインドする
Object.bindProperties
を使用して、あるオブジェクトから別のオブジェクトにプロパティをバインドできます。
var first = {
name: "Whiskey",
age: 5
};
var second = {
volume: 100
};
Object.bindProperties(first, second);
print(first.volume);
second.volume = 1000;
print(first.volume);
これは「ライブ」バインディングであり、ソースオブジェクトに対する更新もバインディングターゲットを通して見ることができます。
7.8. 場所
現在のファイル名、ディレクトリ、および行は、グローバル変数
_FILE
_
、
DIR
、
LINE
__から取得できます。
print(____FILE____, ____LINE____, ____DIR____)
7.9. String.prototype
の拡張
Nashorn
が
String
プロトタイプに対して提供する、2つの単純で非常に便利な拡張があります。これらは
trimRight
と
trimLeft
関数で、驚くことに、空白を削除した
String
のコピーを返します。
print(" hello world".trimLeft());
print("hello world ".trimRight());
前後にスペースを入れずに「hello world」を2回印刷します。
7.10. __Java.asJSON互換性のある機能
この関数を使うことで、Java JSONライブラリの期待と互換性のあるオブジェクトを取得することができます。
つまり、それ自体、またはそれを通して推移的に到達可能な任意のオブジェクトがJavaScript配列の場合、そのようなオブジェクトは
JSObject
として公開されます。これは、配列要素を公開するための
List
インターフェースも実装します。
Object obj = engine.eval("Java.asJSONCompatible(
{ number: 42, greet: 'hello', primes:[2,3,5,7,11,13]})");
Map<String, Object> map = (Map<String, Object>)obj;
System.out.println(map.get("greet"));
System.out.println(map.get("primes"));
System.out.println(List.class.isAssignableFrom(map.get("primes").getClass()));
これにより、“
hello
”の後に
[2、3、5、7、11、13]
の後に__trueが続きます。
8.スクリプトを読み込む
ScriptEngine
内から別のJavaScriptファイルを読み込むこともできます。
load('classpath:script.js')
スクリプトはURLからロードすることもできます。
load('/script.js')
JavaScriptには名前空間の概念がないため、すべてがグローバルスコープに組み込まれていることに注意してください。これにより、ロードされたスクリプトがあなたのコードまたはお互いに命名の衝突を引き起こすことが可能になります。これは、
loadWithNewGlobal
関数を使用して軽減できます。
var math = loadWithNewGlobal('classpath:math__module.js')
math.increment(5);
次の
math
module.js__を使って:
var math = {
increment: function(num) {
return ++num;
}
};
math;bai
ここでは
incrementという単一の関数を持つ
math__という名前のオブジェクトを定義しています。
8結論
この記事では、
__ Nashorn J
avaScriptエンジンのいくつかの機能について説明しました。ここで紹介する例では文字列リテラルスクリプトを使用しましたが、実際のシナリオでは、スクリプトを別々のファイルに保存して
Reader__クラスを使用してロードすることをお勧めします。
いつものように、この記事のコードはすべてhttps://github.com/eugenp/tutorials/tree/master/core-java[over on Github]です。