JavaScriptの互換性
GraalVMは、ECMAScript準拠のJavaScript言語ランタイムです。このドキュメントでは、JavaScriptで記述されたユーザー・アプリケーション用に提供されているパブリックAPIについて説明します。
ECMAScript言語コンプライアンス
GraalVM JavaScriptには、ECMAScript (ECMA-262)仕様の規定に従ってJavaScriptが実装されています。ECMAScript 2022仕様(13エディションまたはES13と呼ばれることもある)と完全な互換性があります。ECMAScript 2023に組み込まれたことが確認された新機能は、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)が提供されています。
追加のオブジェクトは、Intl
(フラグ: --js.intl-402
)などのフラグで使用できます。使用可能なフラグのリストを表示するには、js --help
またはjs --help:languages
を実行します。
これらの関数オブジェクトのいくつかとそのメンバーの一部は、特定のバージョンの仕様が実行用に選択されている場合にのみ使用できます。提供されているメソッドのリストについては、ECMAScript仕様を調べてください。仕様に対する拡張機能は次のとおりです。
国際化API (ECMA-402)
国際化API実装(https://tc39.github.io/ecma402を参照)は、--js.intl-402=true
フラグを使用してアクティブ化できます。ネイティブ・モード(デフォルト・オプション)で実行する場合は、--vm.Dcom.ibm.icu.impl.ICUBinary.dataPath=$GRAAL_VM_DIR/jre/languages/js/icu4j/icudt
オプションを使用してICUデータ・ディレクトリへのパスも指定する必要があります。$GRAAL_VM_DIR
は、GraalVMのインストール・ディレクトリです。JVMモード(--jvm
フラグを使用)で実行する場合は、ICUデータの場所を前述のオプションで指定できますが、必須ではありません。
国際化APIをアクティブ化すると、次の組込み機能を使用できるようになります:
Intl.NumberFormat
Intl.DateTimeFormat
Intl.Collator
Intl.PluralRules
他のいくつかの組込み機能も、前述の仕様に従って更新されます。
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つの引数(rejection、promise)でコールされます。
Graal.setUnhandledPromiseRejectionHandler
を、null、未定義または空の引数でコールすると、ハンドラをクリアできます。
Java
Java
オブジェクトは、エンジンがJVMモード(--jvm
フラグ)で起動された場合にのみ使用できます。
一部の関数ではNashorn互換性モード・フラグを設定する必要があることに注意してください。GraalVMでは、このフラグは次のように設定できます:
js --jvm --experimental-options --js.nashorn-compat=true
Java.type(className)
- 指定されたJavaクラスをロードし、オブジェクトとして提供します
- このオブジェクトのフィールドはそれ自体から直接読み取ることができ、新しいインスタンスはJavaScriptの
new
キーワードを使用して作成できます:var BigDec = Java.type('java.math.BigDecimal'); var bd = new BigDec("0.1"); console.log(bd.add(bd).toString());
Java.from(javaData)
- Javaデータ構造(配列、リスト)のシャロー・コピーをJavaScript配列として作成します
多くの場合、これは不要です。通常、JavaScriptから直接Javaデータ構造を使用できます。
Java.to(jsData, toType)
- 引数をJavaデータ型に変換します
ソース・オブジェクトjsData
は、JavaScript配列またはlength
プロパティを持つオブジェクトである必要があります。ターゲットtoType
は、文字列(例: "int[]"
)または型オブジェクト(例: Java.type("int[]")
)のいずれかです。有効なターゲット型はJava配列です。ターゲット型の指定がなければ、Object[]
とみなされます:
var jsArr = ["a", "b", "c"];
var strArrType = Java.type("java.lang.String[]");
var javaArr = Java.to(jsArr, strArrType);
assertEquals('class java.lang.String[]', String(javaArr.getClass()));
ECMAScriptで定義されている変換メソッド(ToString
やToDouble
など)は、JavaScript値をJava型に変換する必要がある場合に実行されます。非可逆変換は許可されていないため、TypeErrorになります。
Java.isJavaObject(obj)
obj
がJava言語のオブジェクトかどうかを返します- ネイティブ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互換性モード・フラグが必要です。
Java.isScriptObject(obj)
obj
がJavaScript言語のオブジェクトかどうかを返します- Javaオブジェクトや他のポリグロット言語のオブジェクトなど、他のすべての型に対しては
false
を返します
この関数には、Nashorn互換性モード・フラグが必要です。
Java.isScriptFunction(fn)
fn
がJavaScript関数かどうかを返します- Java関数や他のポリグロット言語の関数など、他のすべての型に対しては
false
を返します
この関数には、Nashorn互換性モード・フラグが必要です。
Java.addToClasspath(location)
- 指定された場所(文字列としてのファイル名またはパス名)を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
の値は、実行時にロードされたコードに渡されます。