SpiderMonkey学习笔记(3)--实现alert()函数

上一篇文章把SpiderMonkey引擎简单的封装了一下,实现了JsEngine类。但是JsEngine并没有给SpiderMonkey添加任何扩展,所以能力相当有限,甚至连个alert()函数也没有微笑这一篇就来看一看,如何扩展SpiderMonkey引擎,把自定义的C++ alert()函数暴露给JS。

1)添加新类:JsEngine2

添加一个新类,就起名叫JsEngine2吧(多没创意的名字啊!)。如果不知道如何添加一个新类,翻一翻 前一篇文章
SpiderMonkey学习笔记(3)--实现alert()函数_第1张图片
编辑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!');");
}
启动虚拟机:
SpiderMonkey学习笔记(3)--实现alert()函数_第2张图片
Hello World!成功的打印了出来!



你可能感兴趣的:(SpiderMonkey学习笔记(3)--实现alert()函数)