SpiderMonkey
从源码中建立 SpiderMonkey 看 SpiderMonkey Build Documentation(https://developer.mozilla.org/En/SpiderMonkey/Build_Documentation).
一些系统(例如 Debian) 提供了预设包。 代替从源码中建立 SpiderMonkey。 你的程序更容易调试。
c++ 代码使用 SpiderMonkey 是通过 JSAPI, 输入头文件 “jsapi.h”. 下面是 JSAPI 功能概述。 更多细节请看JSAPI Reference.
SpiderMonkey世界
为了在SpiderMonkey中运行任何的JavaScript代码, 一个应用必须要有3个关键因素:一个 JSRuntime, 一个 JSContext, 和一个 global object. 这节描述这些是什么。 下节解释如何通过JSAPI设立他们。
Runtimes。
一个JSRuntime 或者 runtime, 是一个空间,其中分配着JavaScript 变量, 对象, 脚本, 和上下文 被你的应用所使用。 在应用中的每一个JSContext 和每一个对象 都活在JSRuntime中。 他们不能游历或者共享到另一个runtimes中。 大多数应用只需要一个runtime。
Contexts。
一个JSContext 或者 context, 更像一个小机器, 能够做很多涉及到js代码 和 对象 的事。 他能够编译和运行脚本, get 和 set 对象属性, 调用 js函数, 转换js数据 从一个类型到另一个类型, 创建对象, 等等。 大多数JSAPI 函数需要一个JSContext* 作为开头声明, 犹如大多数
using namespace JS;
// The class of the global object. 全局对象
static JSClass globalClass = {
“global”,
JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub,
JS_DeletePropertyStub,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};
// The error reporter callback. 错误处理回调
void reportError(JSContext *cx, const char *message, JSErrorReport *report) {
fprintf(stderr, “%s:%u:%s\n”,
report->filename ? report->filename : “[no filename]”,
(unsigned int) report->lineno,
message);
}
int run(JSContext *cx) {
// Enter a request before running anything in the context.输入一个请求
JSAutoRequest ar(cx);
// Create the global object and a new compartment.创建一个对象
//声明对象
RootedObject global(cx);
//
global = JS_NewGlobalObject(cx, &globalClass, nullptr,
JS::DontFireOnNewGlobalHook);
if (!global)
return 1;
// Enter the new global object's compartment.
JSAutoCompartment ac(cx, global);
// Populate the global object with the standard globals, like Object and
// Array.
if (!JS_InitStandardClasses(cx, global))
return 1;
// Your application code here. This may include JSAPI calls to create your
// own custom JS objects and run scripts.
return 0;
}
int main(int argc, const char *argv[]) {
// Initialize the JS engine.
if (!JS_Init())
return 1;
// Create a JS runtime.
JSRuntime *rt = JS_NewRuntime(8L * 1024L * 1024L);
if (!rt)
return 1;
// Create a context.
JSContext *cx = JS_NewContext(rt, 8192);
if (!cx)
return 1;
JS_SetErrorReporter(rt, reportError);
int status = run(cx);
// Shut everything down.
JS_DestroyContext(cx);
JS_DestroyRuntime(rt);
JS_ShutDown();
return status;
}
每个jsnative具有相同的签名, 无论从js众接收到任何的参数。
JavaScript函数的参数是argc和vp。 argc说明发来了多少个实际参数, JS_ARGV(cx, vp) (高版本使用 JS::CallArgs args = JS::CallArgsFromVp(argc, vp); ) 返回一个数组,里面包含了这些参数。 这些参数不是传统的c++类型,例如int float; 而是jsvals, js类型。 使用 JS_ConvertArguments转换到c++类型,并储存在局部变量中。 使用 JS_SET_RVAL(cx, vp, val)(高版本使用args.rval().set(jsret);)返回给js的值。
如果成功, JSNative会调用JS_SET_RVAL并返回true。 该值会通过JS_SET_RVAL返回给js调用者。
如果失败, JSNative调用一个error-reporting函数, 该例为JS_ReportError, 并且返回错误。 这会导致js抛出一个异常。 调用者能通过js的 try/catch 捕获异常。
让js能够调用native的函数, 通过 JSFunctionSpec 声明一个表格来描述函数。然后调用 JS_DefineFunctions(高版本调用JS_DefineFunction 一个个函数设置).
static JSFunctionSpec myjs_global_functions[] = {
JS_FS(“rand”, myjs_rand, 0, 0),
JS_FS(“srand”, myjs_srand, 0, 0),
JS_FS(“system”, myjs_system, 1, 0),
JS_FS_END
};
...
if (!JS_DefineFunctions(cx, global, myjs_global_functions))
return false;
...
一旦函数被定义到global中, 任何的脚本使用global都能调用他们, 就像任何的网页能调用alert。 在环境中我们创建 “hello world” 脚本 像下面:
system(“echo hello world”);