本文主要是介绍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!
这篇关于SpiderMonkey学习笔记(4)--实现max()函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!