- 适用于 JDK 24 的 GraalVM(最新)
- 适用于 JDK 25 的 GraalVM(早期访问)
- 适用于 JDK 21 的 GraalVM
- 适用于 JDK 17 的 GraalVM
- 存档
- 开发构建
GraalJS 兼容性
GraalJS 是一个符合 ECMAScript 标准的 JavaScript 语言运行时。本文档解释了它为用 JavaScript 编写的用户应用程序提供的公共 API。
ECMAScript 语言合规性 #
GraalJS 实现了 ECMAScript (ECMA-262) 规范,并完全兼容 ECMAScript 2024 规范(有时称为第15版)。当新功能被确认为 ECMAScript 2024 的一部分时,会频繁地添加到 GraalVM 中,详情请参阅 CHANGELOG.md。从 ECMAScript 5 开始的旧版本可以通过配置选项启用(按数字:--js.ecmascript-version=5
或按年份:--js.ecmascript-version=2024
)。在生产环境中,您可能需要考虑指定一个固定的 ECMAScript 版本,因为未来版本的 GraalJS 一旦可用将使用更新的规范版本。
GraalJS 在全局作用域中提供了 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。
其他对象可通过选项获取,例如 --js.temporal
。运行 js --help
可查看可用选项列表。
其中一些函数对象及其部分成员仅在选择特定规范版本执行时可用。有关所提供方法的列表,请查阅 ECMAScript 规范。对规范的扩展如下所述。
国际化 API (ECMA-402) #
GraalJS 附带了 ECMA-402 国际化 API 的实现,默认启用(可以使用以下选项禁用:--js.intl-402=false
)。这包括以下扩展:
Intl.Collator
Intl.DateTimeFormat
Intl.DisplayNames
Intl.ListFormat
Intl.Locale
Intl.NumberFormat
Intl.PluralRules
Intl.RelativeTimeFormat
Intl.Segmenter
根据 ECMA-402 规范,一些其他内置函数(例如 toLocaleString
)的功能也得到了更新。
JavaScript 模块 #
GraalJS 支持 ECMAScript 6 及更高版本定义的模块。请注意,对此功能的支持仍在不断增强。请务必使用最新的 ECMAScript 版本以获取所有最新功能。
通过多语言 Source
加载模块时,您可以使用非官方的 application/javascript+module
MIME 类型来指定您正在加载一个模块。从文件加载 JavaScript 代码时,请确保模块是从 .mjs 扩展名的文件中加载的。使用 import
关键字加载不受此限制,可以从任何扩展名的文件 import
。
兼容性扩展 #
GraalJS 中提供了以下对象和方法,以兼容其他 JavaScript 引擎。请注意,这些方法的行为可能不完全符合所有现有引擎中这些方法的语义。
语言特性 #
条件 Catch 子句
如果启用了 js.syntax-extensions
选项,GraalJS 支持条件 catch 子句。
try {
myMethod(); // can throw
} catch (e if e instanceof TypeError) {
print("TypeError caught");
} catch (e) {
print("another Error caught");
}
全局属性 #
load(source)
- 加载(解析并执行)指定的 JavaScript 源代码
Source 可以是以下类型:
- 字符串:源文件的路径或要执行的 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
对象,它提供多种用于调试目的的方法。这些方法力求提供与其他引擎类似的功能,但不保证结果完全相同。
请注意,当 GraalJS 在 Node.js 模式下执行时(例如,启动 node
可执行文件而不是 js
),这些方法的行为会有所不同。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
Shell 中的附加全局函数 #
quit(status)
- 退出引擎并返回指定的退出代码
read(file)
- 读取
file
的内容
结果以字符串形式返回。
参数 file
可以是以下类型:
java.io.File
:直接使用该文件。- 所有其他类型:
file
被转换为字符串并解释为文件名。
readbuffer(file)
- 读取
file
的内容,类似于read
函数
结果以 JavaScript ArrayBuffer
对象形式返回。
readline()
- 从输入流中读取一行输入
结果以字符串形式返回。
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 脚本模式 #
GraalJS 提供与 Nashorn 引擎兼容的脚本模式。通过 js.scripting
选项启用。请确保设置了 --experimental-options
js --experimental-options --js.scripting=true
在脚本模式下,全局对象中会添加多个属性和函数,包括 readFully、readLine、$ARG
、$ENV
和 $EXEC
。
对于之前面向 Nashorn 或 Rhino 引擎的代码,有可用的迁移指南。
GraalJS 扩展 #
Graal 对象 #
Graal
对象作为全局对象的属性提供。它提供特定于 Graal 的信息。该属性的存在可以用来识别 GraalJS 是否是当前的语言引擎。
if (typeof Graal != 'undefined') {
print(Graal.versionECMAScript);
print(Graal.versionGraalVM);
print(Graal.isGraalRuntime());
}
Graal 对象在 GraalJS 中默认可用,除非通过选项(js.graal-builtin=false
)停用。
Graal.versionECMAScript
- 提供 GraalJS ECMAScript 兼容模式的版本号(年份值)
Graal.versionGraalVM
- 如果当前引擎在 GraalVM 上执行,则提供 GraalVM 的版本
Graal.isGraalRuntime()
- 指示 GraalJS 是否在启用了 GraalVM 的运行时上执行
- 如果为
true
,热点代码将由 Graal 编译器编译,从而实现高吞吐性能。 - 如果为
false
,GraalJS 将不会被 Graal 编译器优化,通常会导致性能降低。
Graal.setUnhandledPromiseRejectionHandler(handler)
#
- 在使用选项(
js.unhandled-rejections=handler
)时提供未处理的 Promise 拒绝处理程序。 - 处理程序会带两个参数被调用:(rejectionReason, unhandledPromise)。
Graal.setUnhandledPromiseRejectionHandler
可以通过传入null
、undefined
或空参数来清除处理程序。
Java #
Java
对象仅在允许 宿主类查找 时可用。要访问 Java 宿主类及其成员,它们首先需要通过 宿主访问策略 允许,并且在从原生可执行文件运行时,需要注册 运行时反射。
请注意,某些功能需要设置 Nashorn 兼容模式(--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 数据结构(Array、List)浅复制为 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()));
当 JavaScript 值必须转换为 Java 类型时,会执行 ECMAScript 定义的转换方法(例如 ToString
和 ToDouble
)。有损转换是不允许的,会导致 TypeError
。
Java.isJavaObject(obj)
- 如果
obj
是一个 Java 宿主对象,则返回true
- 对于原生 JavaScript 对象以及其他多语言的对象,返回
false
Java.isType(obj)
- 如果
obj
是一个表示 Java 类构造函数和静态成员的对象(通过Java.type()
或包对象获得),则返回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 的 classpath 中
多语言 #
Polyglot
对象的功能允许与来自其他多语言的值进行交互。
Polyglot
对象默认可用,除非通过将 js.polyglot-builtin
选项设置为 false
来停用。
Polyglot.export(key, value)
- 将 JavaScript
value
以key
(字符串)名称导出到多语言绑定中function helloWorld() { print("Hello, JavaScript world"); } Polyglot.export("helloJSWorld", helloWorld);
如果多语言绑定中已存在由 key
标识的值,则会被新值覆盖。value
可以是任何有效的 Polyglot 值。
- 如果
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 pyArray = Polyglot.eval('python', 'import random; [random.uniform(0.0, 1.0) for _ in range(1000)]');
当传入无效的 languageId
、语言无法评估 sourceCode
或执行的程序抛出异常时,可能会发生异常。
Polyglot.evalFile(languageId, sourceFileName)
- 使用由
languageId
标识的解释器解析文件sourceFileName
sourceFileName
的值预计为字符串(或可转换为字符串的类型),表示当前路径可访问的文件。
- 返回一个可执行对象,通常是一个函数
var rFunc = Polyglot.evalFile('R', 'myExample.r'); var result = rFunc();
当传入无效的 languageId
、找不到由 sourceFileName
标识的文件,或语言在解析期间抛出异常(例如,语法错误等解析时错误)时,可能会发生异常。评估程序抛出的异常只会在结果函数被评估时才会被抛出。
当 Polyglot
内置功能可用时,Polyglot.evalFile
函数默认可用,除非通过将 js.polyglot-evalfile
选项设置为 false
来停用。当 js.debug-builtin
被激活时,它也可用。
调试 #
- 需要使用
js.debug-builtin
选项启动引擎
Debug
是一个 GraalJS 特定的函数对象,它为调试 JavaScript 代码和 JavaScript 引擎提供功能。此 API 可能会在不另行通知的情况下更改。请勿用于生产目的。
全局函数 #
printErr(...arg)
- 行为与
print
完全相同
唯一的区别是使用错误流进行打印,而不是默认输出流。
loadWithNewGlobal(source, arguments)
- 行为类似于
load
函数
相关的区别在于代码是在一个新的全局作用域(根据 ECMAScript 定义的 Realm)中进行评估的。
Source 可以是以下类型:
java.lang.URL
:查询该 URL 以获取要执行的源代码。- JavaScript 对象:查询该对象以获取
name
和script
属性。 - 所有其他类型:源被转换为字符串。
arguments
的值在执行时提供给加载的代码。