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

2024-01-26 06:32

本文主要是介绍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()函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/645916

相关文章

使用animation.css库快速实现CSS3旋转动画效果

《使用animation.css库快速实现CSS3旋转动画效果》随着Web技术的不断发展,动画效果已经成为了网页设计中不可或缺的一部分,本文将深入探讨animation.css的工作原理,如何使用以及... 目录1. css3动画技术简介2. animation.css库介绍2.1 animation.cs

Java进行日期解析与格式化的实现代码

《Java进行日期解析与格式化的实现代码》使用Java搭配ApacheCommonsLang3和Natty库,可以实现灵活高效的日期解析与格式化,本文将通过相关示例为大家讲讲具体的实践操作,需要的可以... 目录一、背景二、依赖介绍1. Apache Commons Lang32. Natty三、核心实现代

SpringBoot实现接口数据加解密的三种实战方案

《SpringBoot实现接口数据加解密的三种实战方案》在金融支付、用户隐私信息传输等场景中,接口数据若以明文传输,极易被中间人攻击窃取,SpringBoot提供了多种优雅的加解密实现方案,本文将从原... 目录一、为什么需要接口数据加解密?二、核心加解密算法选择1. 对称加密(AES)2. 非对称加密(R

基于Go语言实现Base62编码的三种方式以及对比分析

《基于Go语言实现Base62编码的三种方式以及对比分析》Base62编码是一种在字符编码中使用62个字符的编码方式,在计算机科学中,,Go语言是一种静态类型、编译型语言,它由Google开发并开源,... 目录一、标准库现状与解决方案1. 标准库对比表2. 解决方案完整实现代码(含边界处理)二、关键实现细

python通过curl实现访问deepseek的API

《python通过curl实现访问deepseek的API》这篇文章主要为大家详细介绍了python如何通过curl实现访问deepseek的API,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编... API申请和充值下面是deepeek的API网站https://platform.deepsee

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

SpringBoot实现二维码生成的详细步骤与完整代码

《SpringBoot实现二维码生成的详细步骤与完整代码》如今,二维码的应用场景非常广泛,从支付到信息分享,二维码都扮演着重要角色,SpringBoot是一个非常流行的Java基于Spring框架的微... 目录一、环境搭建二、创建 Spring Boot 项目三、引入二维码生成依赖四、编写二维码生成代码五

MyBatisX逆向工程的实现示例

《MyBatisX逆向工程的实现示例》本文主要介绍了MyBatisX逆向工程的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录逆向工程准备好数据库、表安装MyBATisX插件项目连接数据库引入依赖pom.XML生成实体类、

C#实现查找并删除PDF中的空白页面

《C#实现查找并删除PDF中的空白页面》PDF文件中的空白页并不少见,因为它们有可能是作者有意留下的,也有可能是在处理文档时不小心添加的,下面我们来看看如何使用Spire.PDFfor.NET通过C#... 目录安装 Spire.PDF for .NETC# 查找并删除 PDF 文档中的空白页C# 添加与删

Java实现MinIO文件上传的加解密操作

《Java实现MinIO文件上传的加解密操作》在云存储场景中,数据安全是核心需求之一,MinIO作为高性能对象存储服务,支持通过客户端加密(CSE)在数据上传前完成加密,下面我们来看看如何通过Java... 目录一、背景与需求二、技术选型与原理1. 加密方案对比2. 核心算法选择三、完整代码实现1. 加密上