Rhino 语法兼容 — 与浏览器的差异速查
为什么需要关心
AutoJs6 的 JavaScript 引擎是 Rhino(Mozilla 维护的开源实现),不是浏览器的 V8/WebCore。虽然两者都是 ES 标准的实现,但:
- Rhino 的目标是嵌入式脚本引擎,不是页面渲染
- AutoJs6 运行在 Android JVM 上,可以直接调用 Java API
- 部分浏览器特有的 API(DOM、BOM)不存在
速查表
✅ 完全支持
| 特性 | 说明 |
|---|
var / let / const | 三种声明都支持 |
| 函数声明 | function f() {} |
| 箭头函数 | (x) => x * 2 |
| 对象 / 数组字面量 | {a: 1}, [1, 2, 3] |
if-else / switch | 条件分支 |
for / while / do-while | 循环 |
for...in | 遍历对象属性 |
for...of | 遍历可迭代对象 |
forEach / map / filter | 数组高阶方法 |
String.prototype.* | 几乎全部字符串方法 |
Number.prototype.* | 几乎全部数字方法 |
Object.values() | v6.5+ Rhino 升级后支持 |
Array.prototype.includes() | v6.5+ 支持 |
BigInt | v6.5+ 支持 |
| 模板字符串 | v6.5+ 支持 |
| 默认参数 | function f(a = 1) {} |
| 剩余参数 | function f(...args) {} |
| 解构赋值(对象) | let {a, b} = obj |
| Unicode 辅助平面转义 | '\u{1D160}' |
| 正则标志 | i, m, s, u(v6.7 增强) |
| 后瞻断言 | (?=...), (?<=...)(v6.7 支持) |
| 字符串方法 | startsWith, endsWith, repeat 等 |
JSON.parse / JSON.stringify | 完全支持 |
Math.* | 大部分支持 |
Date | 完整支持 |
RegExp | 基本完整(某些边缘特性需测试) |
try-catch-finally | 完整支持 |
throw | 完整支持 |
Error 对象 | 完整支持 |
structuredClone() | v6.7 新增全局方法 |
⚠️ 部分支持或需测试
| 特性 | 状态 | 说明 |
|---|
async/await | ❌ 不支持 | Rhino 没有 async/await |
Promise | ⚠️ 有限 | 基础 .then().catch() 可用,复杂场景需测试 |
类(class) | ⚠️ 部分 | 基础 class Foo {} 能用,继承和静态方法需测试 |
| 数组解构 | ⚠️ 有限 | let [a, b] = arr 可能有问题 |
| 扩展运算符 | ⚠️ 部分 | 对象 {...obj} 可用,数组 [...arr] 需测试 |
Symbol | ⚠️ 有限 | 基础 Symbol 可用,迭代器需测试 |
Map / Set | ⚠️ 需测试 | 基础增删查改可能可用 |
Proxy | ❌ 不支持 | Rhino 没有实现 Proxy |
Reflect | ❌ 不支持 | - |
generator / yield | ❌ 不支持 | - |
function* | ❌ 不支持 | - |
❌ 不存在的浏览器 API
| API | 替代方案 |
|---|
window | 无替代(非浏览器) |
document | 无替代(非浏览器) |
navigator | 用 device 模块 |
location | 无替代 |
localStorage / sessionStorage | 用 storage 模块 |
fetch() | 用 http.get() / http.post() |
XMLHttpRequest | 用 http 模块 |
WebSocket(浏览器版) | 用 WebSocketType 模块 |
setTimeout / setInterval(浏览器版) | 有全局版本,行为略有不同 |
requestAnimationFrame | 无 |
console.log()(浏览器版) | 有全局版本 |
alert() / confirm() / prompt() | 用 dialogs 模块 |
atob() / btoa() | 用 base64 模块 |
crypto(浏览器版) | 用 crypto 模块 |
Rhino vs V8 代码对比
网络请求
// ❌ 浏览器写法(V8)
fetch("https://api.example.com/data")
.then(r => r.json())
.then(data => console.log(data));
// ✅ AutoJs6 写法(Rhino)
let response = http.get("https://api.example.com/data");
let data = response.body.json();
console.log(data);
弹窗
// ❌ 浏览器
alert("提示");
let name = prompt("请输入名字");
let confirmed = confirm("确定吗?");
// ✅ AutoJs6
dialogs.alert("提示");
let name = dialogs.prompt("请输入名字");
let confirmed = dialogs.confirm("确定吗?");
本地存储
// ❌ 浏览器
localStorage.setItem("key", "value");
let val = localStorage.getItem("key");
localStorage.removeItem("key");
// ✅ AutoJs6
storage.put("key", "value");
let val = storage.get("key");
storage.remove("key");
定时器
// ❌ 浏览器(返回 Timer 对象)
let timer = setInterval(fn, 1000);
clearInterval(timer);
// ✅ AutoJs6(用法基本一样)
let timer = setInterval(fn, 1000);
clearInterval(timer);
// 注意:AutoJs6 的 setTimeout/setInterval 是全局实现,
// 不是浏览器原生的,行为有细微差异
异步等待
// ❌ 浏览器
let response = await fetch(url);
let data = await response.json();
// ✅ AutoJs6
// Rhino 不支持 await,用回调或 Promise 链
http.getAsync(url).then(response => {
let data = response.body.json();
console.log(data);
});
弹窗
// ❌ 浏览器
alert("完成");
// ✅ AutoJs6
toast("完成"); // 短暂提示(非阻塞)
dialogs.alert("完成"); // 模态对话框(阻塞)
Java 互操作(Rhino 独有能力)
Rhino 最大的优势是可以直接调用 Java API,这是浏览器做不到的:
// 直接使用 Java 类
let javaFile = new java.io.File("/sdcard");
console.log("存在: " + javaFile.exists());
console.log("是目录: " + javaFile.isDirectory());
// 使用 Android API
let Intent = android.content.Intent;
let intent = new Intent();
intent.setClassName("com.android.settings", ".Settings");
context.startActivity(intent);
// 反射调用
let Class = java.lang.Class;
let System = java.lang.System;
System.out.println("Hello from Rhino!");
兼容性测试技巧
遇到不确定的语法时,直接在 AutoJs6 里测试:
// 写个测试脚本逐个验证
let features = [
{ name: "BigInt", test: () => typeof 567n === "bigint" },
{ name: "includes", test: () => [1,2,3].includes(2) },
{ name: "模板字符串", test: () => `hello ${1+1}` === "hello 2" },
{ name: "Promise", test: () => Promise.resolve(1) instanceof Promise },
{ name: "async", test: () => typeof (async () => {}) === "function" },
{ name: "Proxy", test: () => new Proxy({}, {}) instanceof Object }
];
features.forEach(f => {
try {
let ok = f.test();
console.log((ok ? "✅ " : "❌ ") + f.name);
} catch (e) {
console.log("❌ " + f.name + " (报错: " + e.message + ")");
}
});
版本间差异
| AutoJs6 版本 | Rhino 版本 | 新增支持 |
|---|
| v6.4 及以前 | v1.7.7.2 | ES5 完整 + ES6 部分 |
| v6.5 | v2.0.0-alpha | BigInt、模板字符串、Object.values、辅助平面 Unicode |
| v6.6 | v2.0.0-SNAPSHOT | 更多 ES2020 特性 |
| v6.7 | v2.0.0-SNAPSHOT | 正则后瞻断言、标志位、structuredClone |
避免踩坑清单
| 坑 | 解法 |
|---|
照搬浏览器教程的 document.getElementById() | 改用控件选择器 id("xxx").findOne() |
用 fetch() 做网络请求 | 改用 http.get() |
localStorage.setItem 保存配置 | 改用 storage.put() |
async/await 异步控制流程 | 改用回调 / Promise 链 / engines.execScript |
依赖 setTimeout 精准时序 | 改用 sleep() + waitFor |
脚本开头写 "use strict" | Rhino 支持但不强制,通常不需要 |
忘了 auto.waitFor() | 每个自动化脚本开头加 "auto"; auto.waitFor(); |