上一篇文章把SpiderMonkey引擎简单的封装了一下,实现了JsEngine类。但是JsEngine并没有给SpiderMonkey添加任何扩展,所以能力相当有限,甚至连个alert()函数也没有
这一篇就来看一看,如何扩展SpiderMonkey引擎,把自定义的C++ alert()函数暴露给JS。
1)添加新类:JsEngine2
添加一个新类,就起名叫JsEngine2吧(多没创意的名字啊!)。如果不知道如何添加一个新类,翻一翻
前一篇文章
编辑JsEngine2.h,添加JsEngine2类,并让它继承JsEngine:
#include "JsEngine.h"
class JsEngine2 : public JsEngine {
public:
JsEngine2();
virtual ~JsEngine2();
};
2)C++版alert()函数
先请C++版的alert()函数登场!在JsEngine2.cpp的开头添加下面的代码:
static void alert(std::string msg) {
std::cout << msg << "\n";
}这个alert()函数如此平淡无奇,所以也无需过多的解释,接着看如何让JS代码可以使用这个函数。
3)JSNative版alert()函数
为了让JS代码能够调用上面的alert()函数,需要让SpiderMonkey知道alert()这个角色的存在。但问题是,SpiderMonkey的架子特别大,不肯和像alert()这样的无名小辈打交道,所以,我们需要给alert()请一位代理,让他在alert()和SpiderMonkey之间传话。你要是以为谁都可以充当这种代理,那你就太不了解SpiderMonkey了。只有长得像
JSNative的函数才能但当这个重任。JSNative实际上只是个函数签名:
typedef JSBool (*JSNative)(JSContext *cx, unsigned argc, JS::Value *vp);好吧,兜了半天的圈子,请出JSNative版alert:
static JSBool myjs_alert(JSContext *cx, unsigned argc, jsval *vp) {
JSString *str;
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", &str))
return JS_FALSE;
char *msg = JS_EncodeString(cx, str);
alert(msg);
JS_free(cx, msg);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
简单介绍一下myjs_alert()的工作吧:先提取出JSString类型的参数,然后把它编码成C char*字符串,接着就调用alert()函数。然后释放char*字符串,设置JS函数返回值。最后返回JS_TRUE告诉SpiderMonkey函数调用成功。
4)把JSNative版alert()告诉SpiderMonkey
事情总是要比想象中的要复杂那么一点,我们还需要一个步骤,把myjs_alert()介绍给SpiderMonkey认识:
static JSFunctionSpec myjs_global_functions[] = {
JS_FS("alert", myjs_alert, 1, 0),
JS_FS_END
};
JsEngine2::JsEngine2() {
if (!JS_DefineFunctions(cx, global, myjs_global_functions)) {
return;
}
}
如代码所示,先定义一个
JSFunctionSpec数组,第一个元素描述了myjs_alert()函数,第二个元素类似NULL,表示数组结尾。由于JsEngine2继承了JsEngine,而JsEngine的构造函数已经把SpiderMonkey引擎给初始化好了,所以JsEngine2的构造函数直接调用JS_DefineFunctions把alert注册到SpiderMonkey。
5)JsEngine2.cpp完整代码
下面是JsEngine2.cpp的完整代码:
#include <iostream>
#include "JsEngine2.h"
static void alert(std::string msg) {
std::cout << msg << "\n";
}
static JSBool myjs_alert(JSContext *cx, unsigned argc, jsval *vp) {
JSString *str;
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", &str))
return JS_FALSE;
char *msg = JS_EncodeString(cx, str);
alert(msg);
JS_free(cx, msg);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
static JSFunctionSpec myjs_global_functions[] = {
JS_FS("alert", myjs_alert, 1, 0),
JS_FS_END
};
JsEngine2::JsEngine2() {
if (!JS_DefineFunctions(cx, global, myjs_global_functions)) {
return;
}
}
JsEngine2::~JsEngine2() {
}
6)测试JsEngine2
修改ViewController.mm:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
JsEngine2 engine;
engine.execJS("alert('Hello World!');");
}启动虚拟机:
Hello World!成功的打印了出来!
611

被折叠的 条评论
为什么被折叠?



