JavaScriptの互換性
GraalVMは、ECMAScript準拠のJavaScript言語ランタイムです。このドキュメントでは、JavaScriptで記述されたユーザー・アプリケーション用に提供されているパブリックAPIについて説明します。
ECMAScript言語コンプライアンス
GraalVM JavaScriptには、ECMAScript (ECMA-262)仕様の規定に従ってJavaScriptが実装されています。ECMAScript 2023仕様(14エディションと呼ばれることもある)と完全な互換性があります。ECMAScript 2024に組み込まれたことが確認された新機能は、GraalVMに頻繁に追加されています。詳細は、CHANGELOG.mdを参照してください。ECMAScript 5以降の旧バージョンは、構成フラグ(番号: --js.ecmascript-version=5、または年: --js.ecmascript-version=2019)を使用して有効にできます。本番設定では、必要に応じて固定のECMAScriptバージョンを使用するよう指定することを検討してください。GraalVM JavaScriptの将来のバージョンでは、新しいバージョンの仕様が使用可能になった時点でその仕様が使用されるためです。
GraalVM JavaScriptでは、ECMAScriptで指定されたグローバル・スコープでJavaScriptコア・ライブラリを表す関数オブジェクト(Array、ArrayBuffer、Boolean、DataView、Date、Error、Function、JSON、Map、Math、Number、Object、Promise、Proxy、Reflect、RegExp、Set、SharedArrayBuffer、String、Symbol、TypedArray、WeakMapおよびWeakSet)が提供されています。
追加のオブジェクトは、Temporal (フラグ: --js.temporal)などのフラグで使用できます。使用可能なフラグのリストを表示するには、js --helpまたはjs --help:languagesを実行します。
これらの関数オブジェクトのいくつかとそのメンバーの一部は、特定のバージョンの仕様が実行用に選択されている場合にのみ使用できます。提供されているメソッドのリストについては、ECMAScript仕様を調べてください。仕様に対する拡張機能は次のとおりです。
国際化API (ECMA-402)
GraalVM JavaScriptには、ECMA-402国際化APIの実装が付属していて、デフォルトで有効になっています(--js.intl-402=falseフラグを使用して無効にできます)。これには次の拡張機能が含まれます:
Intl.CollatorIntl.DateTimeFormatIntl.DisplayNamesIntl.ListFormatIntl.LocaleIntl.NumberFormatIntl.PluralRulesIntl.RelativeTimeFormatIntl.Segmenter
toLocaleStringなど、他のいくつかの組込み機能も、ECMA-402仕様に従って更新されます。
JavaScriptモジュール
GraalVM JavaScriptは、ECMAScript 6以降で定義されているモジュールをサポートしています。この機能のサポートは徐々に拡張されていることに留意してください。必ず最新のすべての機能に最新のECMAScriptバージョンを使用してください。
ポリグロットSourceを介してモジュールをロードする場合は、非公式のapplication/javascript+module MIMEタイプを使用して、モジュールをロードすることを指定できます。ファイルからJavaScriptコードを使用してロードする場合は、必ず拡張子が.mjsのファイルからモジュールをロードしてください。importキーワードを使用したロードはこの制限を受けず、任意の拡張子のファイルからインポートできます。
互換性拡張機能
GraalVM JavaScriptでは、他のJavaScriptエンジンとの互換性確保のために、次のオブジェクトおよびメソッドを使用できます。このようなメソッドの動作は、既存のすべてのエンジンのメソッドのセマンティクスと厳密に一致しない場合があります。
言語機能
条件付きcatch句
GraalVM JavaScriptでは、js.syntax-extensionsオプションが有効な場合、条件付きcatch句がサポートされます:
try {
myMethod(); // can throw
} catch (e if e instanceof TypeError) {
print("TypeError caught");
} catch (e) {
print("another Error caught");
}
グローバル・プロパティ
load(source)
- 指定したJavaScriptソース・コードをロード(解析および実行)します
ソースの型は次のいずれかです:
- 文字列: 実行するソース・ファイルまたはURLのパスです。
java.lang.URL:js.load-from-urlオプションがtrueに設定されている場合に、URLに対して実行対象のソース・コードを問い合せます。java.io.File: 実行するソース・コードのファイルを読み取ります。- JavaScriptオブジェクト: オブジェクトに対して
nameおよびscriptプロパティを問い合せます。これらのプロパティは、それぞれソース名とコードを表します。 - 他のすべての型: ソースは文字列に変換されます。
loadはデフォルトで使用可能であり、js.loadオプションをfalseに設定することで非アクティブ化できます。
print(...arg)およびprintErr(...arg)
- 引数をコンソールに出力します(それぞれstdoutとstderr)
- 人間が読めるベストエフォート型の出力を提供します
printおよびprintErrはデフォルトで使用可能であり、js.printオプションをfalseに設定することで非アクティブ化できます。
consoleグローバル・オブジェクトのメソッド
デバッグ用に複数のメソッドを提供するグローバルなconsoleオブジェクトが用意されています。これらのメソッドは、他のエンジンと可能なかぎり同じ機能を提供するように設計されていますが、必ずしも同一の結果が保証されるわけではありません。
これらのメソッドの動作は、GraalVM JavaScriptがNode.jsモードで実行された場合(つまり、jsのかわりにnode実行可能ファイルが起動された場合)とは異なることに注意してください。Node.jsには、かわりに使用される独自の実装が用意されています。
console.log、console.infoおよびconsole.debug:print(...arg)の別名ですconsole.errorおよびconsole.warn:printに似ていますが、エラーIOストリームを使用しますconsole.assert(check, message):checkが偽の場合にmessageを出力しますconsole.clear: 可能な場合はコンソール・ウィンドウをクリアしますconsole.count()およびconsole.countReset(): コールされた回数をカウントして出力するか、またはこのカウンタをリセットしますconsole.groupおよびconsole.groupEnd: コンソールへの後続の出力のインデントを増減しますconsole.time()、console.timeLog()およびconsole.timeEnd(): タイマーを開始するか、タイマーがアクティブであった期間を出力するか、または期間を出力してタイマーを停止します
consoleオブジェクトはデフォルトで使用可能であり、js.consoleオプションをfalseに設定することで非アクティブ化できます。
jsシェルの追加のグローバル関数
quit(status)
- エンジンを終了し、指定されたステータス・コードを返します
read(file)
fileの内容を読み取ります
結果は文字列として返されます。
引数fileの型は次のいずれかです:
java.io.File: ファイルが直接使用されます。- 他のすべての型:
fileは文字列に変換され、ファイル名として解釈されます。
readbuffer(file)
read関数と同様に、fileの内容を読み取ります
結果はJavaScriptのArrayBufferオブジェクトとして返されます。
readline()
- 入力ストリームから1行の入力を読み取ります
結果は文字列として返されます。
Object
Object.prototype.__defineGetter__(prop, func)
thisのpropプロパティをgetter関数funcとして定義します
この機能は、ほとんどのJavaScriptエンジンでは非推奨です。最新のECMAScriptバージョンでは、getterおよびsetterは言語によってネイティブにサポートされています。
Object.prototype.__defineSetter__(prop, func)
thisのpropプロパティをsetter関数funcとして定義します
この機能は、ほとんどのJavaScriptエンジンでは非推奨です。最新のECMAScriptバージョンでは、getterおよびsetterは言語によってネイティブにサポートされています。
Object.prototype.__lookupGetter__(prop)
__defineGetter__で設定されたオブジェクトのpropプロパティのgetter関数を返します
この機能は、ほとんどのJavaScriptエンジンでは非推奨です。最新のECMAScriptバージョンでは、getterおよびsetterは言語によってネイティブにサポートされています。
Object.prototype.__lookupSetter__(prop)
__defineSetter__で設定されたオブジェクトのpropプロパティのsetter関数を返します
この機能は、ほとんどのJavaScriptエンジンでは非推奨です。最新のECMAScriptバージョンでは、getterおよびsetterは言語によってネイティブにサポートされています。
Nashornスクリプト・モード
GraalVM JavaScriptには、Nashornエンジンに備わっているものと互換性のあるスクリプト・モードが用意されています。これは、js.scriptingオプションを使用して有効にします。必ず--experimental-optionsを設定してください:
js --experimental-options --js.scripting=true
スクリプト・モードでは、readFully、readLine、$ARG、$ENV、$EXECなど、いくつかのプロパティと関数がグローバル・オブジェクトに追加されます。
これまでNashornエンジンまたはRhinoエンジンにターゲット指定していたコードを移行できるように、移行ガイドが用意されています。
GraalVM JavaScript拡張機能
Graalオブジェクト
Graalオブジェクトは、グローバル・オブジェクトのプロパティとして提供されています。これは、Graal固有の情報を示します。このプロパティの有無で、GraalVM JavaScriptエンジンが現在の言語エンジンであるかどうかを識別できます:
if (typeof Graal != 'undefined') {
print(Graal.versionECMAScript);
print(Graal.versionGraalVM);
print(Graal.isGraalRuntime());
}
Graalオブジェクトは、オプション(js.graal-builtin=false)によって非アクティブ化しないかぎり、デフォルトでGraalVM JavaScriptで使用できます。
Graal.versionECMAScript
- GraalVM JavaScriptのECMAScript互換性モードのバージョン番号(年値)を示します。
Graal.versionGraalVM
- 現在のエンジンがGraalVMで実行されている場合は、GraalVMのバージョンを示します
Graal.isGraalRuntime()
- GraalVM JavaScriptがGraalVM対応ランタイムで実行されるかどうかを示します
trueの場合、ホット・コードはGraalVMコンパイラによってコンパイルされるため、ピーク・パフォーマンスが高くなります。falseの場合、GraalVM JavaScriptはGraalVMコンパイラによって最適化されないため、通常はパフォーマンスが低下します。
Graal.setUnhandledPromiseRejectionHandler(handler)
- オプション(
js.unhandled-rejections=handler)を使用する際に未処理の回答拒否ハンドラを示します。 - このハンドラは、2つの引数(rejectionReason、unhandledPromise)を使用してコールされます。
Graal.setUnhandledPromiseRejectionHandlerをnull、undefinedまたは空の引数でコールすると、ハンドラをクリアできます。
Java
Javaオブジェクトを使用できるのは、ホスト・クラス参照が許可されている場合のみです。Javaホスト・クラスとそのメンバーにアクセスするには、まずホスト・アクセス・ポリシーで許可し、ネイティブ・イメージから実行する場合は、実行時リフレクションに登録する必要があります。
一部の関数では、Nashorn互換性モード・フラグの設定が必要なことに注意してください。JVMスタンドアロン・ディストリビューションから実行する場合、このフラグは次のようにして設定できます:
js --experimental-options --js.nashorn-compat=true
Java.type(className)
Java.typeは、指定されたJavaクラスをロードし、クラスの静的メンバー(メソッドおよびフィールド)のある構築可能オブジェクトを返すもので、newキーワードと一緒に使用して新しいインスタンスを構築できます:
var BigDecimal = Java.type('java.math.BigDecimal');
var point1 = new BigDecimal("0.1");
var two = BigDecimal.TWO;
console.log(point1.multiply(two).toString());
new演算子で直接使用する場合は、Java.type(...)をカッコで囲む必要があります:
console.log(new (Java.type('java.math.BigDecimal'))("1.1").pow(15));
Java.from(javaData)
Java.fromでは、Javaデータ構造(配列、リスト)のシャロー・コピーがJavaScript配列として作成されます。
多くの場合、これは不要です。通常、JavaScriptから直接Javaデータ構造を使用できます。
Java.to(jsData, javaType)
Java.toでは、引数がJava型に変換されます。
ソース・オブジェクトjsDataには、JavaScript配列またはlengthプロパティのある配列と同じようなオブジェクトであることが必要です。ターゲットjavaTypeは、文字列(例: "int[]")または型オブジェクト(例: Java.type("int[]"))のいずれかです。有効なターゲット型はJava配列です。ターゲット・タイプを省略すると、デフォルトでObject[]に設定されます。
var jsArray = ["a", "b", "c"];
var stringArrayType = Java.type("java.lang.String[]");
var javaArray = Java.to(jsArray, stringArrayType);
assertEquals('class java.lang.String[]', String(javaArray.getClass()));
var javaArray = Java.to(jsArray);
assertEquals('class java.lang.Object[]', String(javaArray.getClass()));
ECMAScriptで定義されている変換メソッド(ToStringやToDoubleなど)は、JavaScript値をJava型に変換する必要がある場合に実行されます。非可逆変換は許可されていないため、TypeErrorになります。
Java.isJavaObject(obj)
objがJavaホスト・オブジェクトの場合、trueが返されます- ネイティブJavaScriptオブジェクトおよび他のポリグロット言語のオブジェクトに対しては
falseを返します
Java.isType(obj)
objが、Java.type()またはパッケージ・オブジェクトによって取得されたJavaクラスのコンストラクタおよび静的メンバーを表すオブジェクトの場合は、trueが返されます。- 他のすべての引数に対しては
falseを返します
Java.typeName(obj)
objがJavaタイプ(isType(obj) === true)またはJavaClassインスタンスを表す場合、objのJavaClass名を返します- それ以外の場合、
undefinedを返します
Java.isJavaFunction(fn)
fnがJava関数を表すJava言語のオブジェクトかどうかを返します- ネイティブJavaScript関数や他のポリグロット言語の関数など、他のすべての型に対しては
falseを返します
この関数は、Nashorn互換性モード(
--js.nashorn-compat=true)でのみ使用可能です。
Java.isScriptObject(obj)
objがJavaScript言語のオブジェクトかどうかを返します- Javaオブジェクトや他のポリグロット言語のオブジェクトなど、他のすべての型に対しては
falseを返します
この関数は、Nashorn互換性モード(
--js.nashorn-compat=true)でのみ使用可能です。
Java.isScriptFunction(fn)
fnがJavaScript関数かどうかを返します- Java関数や他のポリグロット言語の関数など、他のすべての型に対しては
falseを返します
この関数は、Nashorn互換性モード(
--js.nashorn-compat=true)でのみ使用可能です。
Java.addToClasspath(location)
- 指定された場所(
.jarファイルまたはディレクトリ・パス文字列)をJavaのクラスパスに追加します
ポリグロット
Polyglotオブジェクトの関数を使用すると、他のポリグロット言語の値と対話できます。
Polyglotオブジェクトは、js.polyglot-builtinオプションをfalseに設定することで非アクティブ化しないかぎり、デフォルトで使用可能です。
Polyglot.export(key, value)
key(文字列)という名前のJavaScriptvalueをポリグロット・バインディングにエクスポートします:function helloWorld() { print("Hello, JavaScript world"); } Polyglot.export("helloJSWorld", helloWorld);
ポリグロット・バインディングにkeyで識別される値がすでに存在する場合は、新しい値で上書きされます。valueには、有効なポリグロット値を任意に指定できます。
keyが文字列でないか見つからない場合にTypeErrorをスローします
Polyglot.import(key)
key(文字列)で識別される値をポリグロット・バインディングからインポートし、それを返します:var rubyHelloWorld = Polyglot.import("helloRubyWorld"); rubyHelloWorld();
keyで識別される値をエクスポートした言語がない場合は、undefinedが返されます。
keyが文字列でないか見つからない場合にTypeErrorをスローします
Polyglot.eval(languageId, sourceCode)
languageIdで識別されたインタプリタでsourceCodeを解析および評価します
sourceCodeの値は、文字列(または文字列に変換可能)である必要があります。
- 評価された言語の
sourceCodeまたはセマンティクス(あるいはその両方)に応じて、評価結果を返します:var rArray = Polyglot.eval('R', 'runif(1000)');
無効なlanguageIdが渡された場合、言語でsourceCodeを評価できない場合、または実行されたプログラムによって例外がスローされた場合、例外が発生することがあります。
Polyglot.evalFile(languageId, sourceFileName)
languageIdで識別されたインタプリタでsourceFileNameファイルを解析します
sourceFileNameの値は、現在のパスによって到達可能なファイルを表す文字列(または文字列に変換可能)である必要があります。
- 実行可能なオブジェクト(通常は関数)を返します:
var rFunc = Polyglot.evalFile('R', 'myExample.r'); var result = rFunc();
無効なlanguageIdが渡された場合、sourceFileNameで識別されたファイルが見つからない場合、または解析時に言語によって例外がスローされた場合(構文エラーなどの解析時エラー)、例外が発生することがあります。評価されたプログラムによってスローされる例外は、結果の関数が評価された後にのみスローされます。
Polyglot.evalFile関数は、js.polyglot-evalfileオプションをfalseに設定することで非アクティブ化しないかぎり、Polyglot組込み機能が使用可能であればデフォルトで使用可能です。また、js.debug-builtinがアクティブ化されている場合にも使用可能です。
デバッグ
js.debug-builtinフラグでエンジンを起動する必要があります
Debugは、JavaScriptコードおよびGraalVM JavaScriptコンパイラのデバッグ機能を提供するGraalVM JavaScript固有の関数オブジェクトです。このAPIは予告なしに変更される場合があります。本番用には使用しないでください。
グローバル関数
printErr(...arg)
printと同様に動作します
唯一の違いは、デフォルトの出力ストリームではなく、エラー・ストリームが出力に使用されることです。
loadWithNewGlobal(source, arguments)
load関数と同様に動作します
関連する違いは、コードが新しいグローバル・スコープ(ECMAScriptで定義されているレルム)で評価されることです。
ソースの型は次のいずれかです:
java.lang.URL: URLに対して実行対象のソース・コードを問い合せます。- JavaScriptオブジェクト: オブジェクトに対して
nameおよびscriptプロパティを問い合せます。 - 他のすべての型: ソースは文字列に変換されます。
argumentsの値は、実行時にロードされたコードに渡されます。