SpiderMonkey学习笔记(4)--实现max()函数

上一篇文章中的JsEngine2对SpiderMonkey稍加扩展,使得JS代码里可以使用alert()函数,但是并没有仔细解释如何使用JSNative。这一篇文章我们看看如何给JS提供一个max()函数,经一步研究JSNative。

1)添加JsEngine3类

添加一个新的C++类,命名为JsEngine3,并让它继承JsEngine2:

// JsEngine3.h
#include "JsEngine2.h"

class JsEngine3 : public JsEngine2 {
public:
    JsEngine3();
    virtual ~JsEngine3();
};


2)添加C++版max()函数

代码如下所示,比较简单,就不多解释了:

// JsEngine3.cpp
#include "JsEngine3.h"

static double max(double a, double b) {
    return a > b ? a : b;
}


3)添加JSNative版max()函数

static JSBool myjs_max(JSContext *cx, unsigned argc, jsval *vp) {
    double a, b;

    if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "dd", &a, &b))
        return JS_FALSE;
    
    double c = max(a, b);
    
    JS_SET_RVAL(cx, vp, DOUBLE_TO_JSVAL(c));
    return JS_TRUE;
}
让我们重点研究一下上面这个函数的实现,关于 JSNative的更多解释可以看这里。首先定义了两个double型临时变量a和b,接着调用JS_ConvertArguments()从vp中提取出a和b。JS_ConvertArguments()函数的使用方式有点像printf,它的第四个参数是一个字符串,后面是VARGs。这里我们传给它一个“dd”,代表两个double,分别赋给a和b。下面是从jsapi.h里面摘出来的JS_ConvertArguments()函数的声明和注释:

/*
 * Format is a string of the following characters (spaces are insignificant),
 * specifying the tabulated type conversions:
 *
 *   b      JSBool          Boolean
 *   c      uint16_t/jschar ECMA uint16_t, Unicode char
 *   i      int32_t         ECMA int32_t
 *   u      uint32_t        ECMA uint32_t
 *   j      int32_t         Rounded int32_t (coordinate)
 *   d      double          IEEE double
 *   I      double          Integral IEEE double
 *   S      JSString *      Unicode string, accessed by a JSString pointer
 *   W      jschar *        Unicode character vector, 0-terminated (W for wide)
 *   o      JSObject *      Object reference
 *   f      JSFunction *    Function private
 *   v      jsval           Argument value (no conversion)
 *   *      N/A             Skip this argument (no vararg)
 *   /      N/A             End of required arguments
 *
 * The variable argument list after format must consist of &b, &c, &s, e.g.,
 * where those variables have the types given above.  For the pointer types
 * char *, JSString *, and JSObject *, the pointed-at memory returned belongs
 * to the JS runtime, not to the calling native code.  The runtime promises
 * to keep this memory valid so long as argv refers to allocated stack space
 * (so long as the native function is active).
 *
 * Fewer arguments than format specifies may be passed only if there is a /
 * in format after the last required argument specifier and argc is at least
 * the number of required arguments.  More arguments than format specifies
 * may be passed without error; it is up to the caller to deal with trailing
 * unconverted arguments.
 */
extern JS_PUBLIC_API(JSBool)
JS_ConvertArguments(JSContext *cx, unsigned argc, jsval *argv, const char *format, ...);
拿到参数a和b以后,调用C++版max()函数求出二者中较大的那个,赋值给临时变量c。然后使用JS_SET_VAL宏设置JS函数的返回值。DOUBLE_TO_JSVAL函数可以把double值转换为jsval。jsval的详细说明可以 看这里。最后返回JS_TRUE告诉SpiderMonkey函数调用成功。

4)注册myjs_max

static JSFunctionSpec myjs_global_functions[] = {
    JS_FS("max", myjs_max, 2, 0),
    JS_FS_END
};

JsEngine3::JsEngine3() {
    if (!JS_DefineFunctions(cx, global, myjs_global_functions)) {
        return;
    }
}
JS_FS宏可以产生一个 JSFunctionSpec,JS_FS_END宏产生一个类似NULL的JSFunctionSpec。最后调用 JS_DefineFunctions函数注册max函数。完整的JsEngine3.cpp代码如下:

#include "JsEngine3.h"

static double max(double a, double b) {
    return a > b ? a : b;
}

static JSBool myjs_max(JSContext *cx, unsigned argc, jsval *vp) {
    double a, b;

    if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "dd", &a, &b))
        return JS_FALSE;
    
    double c = max(a, b);
    
    JS_SET_RVAL(cx, vp, DOUBLE_TO_JSVAL(c));
    return JS_TRUE;
}

static JSFunctionSpec myjs_global_functions[] = {
    JS_FS("max", myjs_max, 2, 0),
    JS_FS_END
};

JsEngine3::JsEngine3() {
    if (!JS_DefineFunctions(cx, global, myjs_global_functions)) {
        return;
    }
}

JsEngine3::~JsEngine3() {
    
}

5)测试max函数

修改ViewController.mm测试一下:

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    JsEngine3 engine;
    engine.execJS("alert(max(3.1415, 4));");
}

运行模拟器,输出中打印出了4!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值