- 适用于 JDK 23 的 GraalVM(最新)
- 适用于 JDK 24 的 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。可以使用配置选项(按数字:--js.ecmascript-version=5
或按年份:--js.ecmascript-version=2024
)启用从 ECMAScript 5 开始的旧版本。在生产环境中,您可能需要考虑指定要使用的固定 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
一些其他内置函数的功能,例如 toLocaleString
,也根据 ECMA-402 规范进行了更新。
JavaScript 模块 #
GraalJS 支持 ECMAScript 6 及更高版本定义的模块。请注意,对该功能的支持仍在不断增加。请务必使用最新的 ECMAScript 版本以获取所有最新功能。
通过 polyglot Source
加载模块时,可以使用非官方的 application/javascript+module
MIME 类型来指定您正在加载模块。从文件加载 JavaScript 代码时,请确保从扩展名为 .mjs 的文件加载模块。使用 import
关键字加载不受此限制,并且可以从任何扩展名的文件进行 import
。
兼容性扩展 #
以下对象和方法在 GraalJS 中可用,以与其他 JavaScript 引擎兼容。请注意,此类方法的行为可能并不严格地匹配所有现有引擎中这些方法的语义。
语言功能 #
条件捕获子句
如果启用了 js.syntax-extensions
选项,GraalJS 支持条件捕获子句
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
,但使用错误 I/O 流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)
- 类似于
read
函数,读取file
的内容
结果以 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 数据结构(数组、列表)的浅层副本,作为 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)
- 将指定的 location(
.jar
文件或目录路径字符串)添加到 Java 的类路径中
多语言 #
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 定义)中执行的。
Source 可以是以下类型
java.lang.URL
:查询 URL 以获取要执行的源代码。- JavaScript 对象:查询对象的
name
和script
属性。 - 所有其他类型:将源代码转换为字符串。
在执行时,将 arguments
的值提供给加载的代码。