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フラグを使用して無効にできます)。これには次の拡張機能が含まれます:

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)

ソースの型は次のいずれかです:

loadはデフォルトで使用可能であり、js.loadオプションをfalseに設定することで非アクティブ化できます。

print(...arg)およびprintErr(...arg)

printおよびprintErrはデフォルトで使用可能であり、js.printオプションをfalseに設定することで非アクティブ化できます。

consoleグローバル・オブジェクトのメソッド

デバッグ用に複数のメソッドを提供するグローバルなconsoleオブジェクトが用意されています。これらのメソッドは、他のエンジンと可能なかぎり同じ機能を提供するように設計されていますが、必ずしも同一の結果が保証されるわけではありません。

これらのメソッドの動作は、GraalVM JavaScriptがNode.jsモードで実行された場合(つまり、jsのかわりにnode実行可能ファイルが起動された場合)とは異なることに注意してください。Node.jsには、かわりに使用される独自の実装が用意されています。

consoleオブジェクトはデフォルトで使用可能であり、js.consoleオプションをfalseに設定することで非アクティブ化できます。

jsシェルの追加のグローバル関数

quit(status)

read(file)

結果は文字列として返されます。

引数fileの型は次のいずれかです:

readbuffer(file)

結果はJavaScriptのArrayBufferオブジェクトとして返されます。

readline()

結果は文字列として返されます。

Object

Object.prototype.__defineGetter__(prop, func)

この機能は、ほとんどのJavaScriptエンジンでは非推奨です。最新のECMAScriptバージョンでは、getterおよびsetterは言語によってネイティブにサポートされています。

Object.prototype.__defineSetter__(prop, func)

この機能は、ほとんどのJavaScriptエンジンでは非推奨です。最新のECMAScriptバージョンでは、getterおよびsetterは言語によってネイティブにサポートされています。

Object.prototype.__lookupGetter__(prop)

この機能は、ほとんどのJavaScriptエンジンでは非推奨です。最新のECMAScriptバージョンでは、getterおよびsetterは言語によってネイティブにサポートされています。

Object.prototype.__lookupSetter__(prop)

この機能は、ほとんどのJavaScriptエンジンでは非推奨です。最新のECMAScriptバージョンでは、getterおよびsetterは言語によってネイティブにサポートされています。

Nashornスクリプト・モード

GraalVM JavaScriptには、Nashornエンジンに備わっているものと互換性のあるスクリプト・モードが用意されています。これは、js.scriptingオプションを使用して有効にします。必ず--experimental-optionsを設定してください:

js --experimental-options --js.scripting=true

スクリプト・モードでは、readFullyreadLine$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

Graal.versionGraalVM

Graal.isGraalRuntime()

Graal.setUnhandledPromiseRejectionHandler(handler)

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で定義されている変換メソッド(ToStringToDoubleなど)は、JavaScript値をJava型に変換する必要がある場合に実行されます。非可逆変換は許可されていないため、TypeErrorになります。

Java.isJavaObject(obj)

Java.isType(obj)

Java.typeName(obj)

Java.isJavaFunction(fn)

この関数は、Nashorn互換性モード(--js.nashorn-compat=true)でのみ使用可能です。

Java.isScriptObject(obj)

この関数は、Nashorn互換性モード(--js.nashorn-compat=true)でのみ使用可能です。

Java.isScriptFunction(fn)

この関数は、Nashorn互換性モード(--js.nashorn-compat=true)でのみ使用可能です。

Java.addToClasspath(location)

ポリグロット

Polyglotオブジェクトの関数を使用すると、他のポリグロット言語の値と対話できます。

Polyglotオブジェクトは、js.polyglot-builtinオプションをfalseに設定することで非アクティブ化しないかぎり、デフォルトで使用可能です。

Polyglot.export(key, value)

ポリグロット・バインディングにkeyで識別される値がすでに存在する場合は、新しい値で上書きされます。valueには、有効なポリグロット値を任意に指定できます。

Polyglot.import(key)

keyで識別される値をエクスポートした言語がない場合は、undefinedが返されます。

Polyglot.eval(languageId, sourceCode)

sourceCodeの値は、文字列(または文字列に変換可能)である必要があります。

無効なlanguageIdが渡された場合、言語でsourceCodeを評価できない場合、または実行されたプログラムによって例外がスローされた場合、例外が発生することがあります。

Polyglot.evalFile(languageId, sourceFileName)

sourceFileNameの値は、現在のパスによって到達可能なファイルを表す文字列(または文字列に変換可能)である必要があります。

無効なlanguageIdが渡された場合、sourceFileNameで識別されたファイルが見つからない場合、または解析時に言語によって例外がスローされた場合(構文エラーなどの解析時エラー)、例外が発生することがあります。評価されたプログラムによってスローされる例外は、結果の関数が評価された後にのみスローされます。

Polyglot.evalFile関数は、js.polyglot-evalfileオプションをfalseに設定することで非アクティブ化しないかぎり、Polyglot組込み機能が使用可能であればデフォルトで使用可能です。また、js.debug-builtinがアクティブ化されている場合にも使用可能です。

デバッグ

Debugは、JavaScriptコードおよびGraalVM JavaScriptコンパイラのデバッグ機能を提供するGraalVM JavaScript固有の関数オブジェクトです。このAPIは予告なしに変更される場合があります。本番用には使用しないでください。

グローバル関数

printErr(...arg)

唯一の違いは、デフォルトの出力ストリームではなく、エラー・ストリームが出力に使用されることです。

loadWithNewGlobal(source, arguments)

関連する違いは、コードが新しいグローバル・スコープ(ECMAScriptで定義されているレルム)で評価されることです。

ソースの型は次のいずれかです:

argumentsの値は、実行時にロードされたコードに渡されます。