quickjs模块封装、类封装

一、模块封装、类封装

  通过quickjs,封装JS模块,然后可以通过import 导入对应模块,还可以导入具体的类。全部代码如下。

  1 #include "quickjs-libc.h"
  2 #include <stdio.h>
  3 #include <inttypes.h>
  4 #include <string.h>
  5 #include "cutils.h"
  6 
  7 static JSClassID button_class_id;
  8 typedef struct _button
  9 {
 10   int val;
 11   const char *name;
 12   int serid;
 13 }Button;
 14 static JSValue JSButtonCreate(JSContext *ctx, JSValueConst val, int argc, JSValueConst *argv)
 15 {
 16   JSValue obj = JS_UNDEFINED;
 17   Button * button = (Button*)js_malloc(ctx, sizeof(Button));
 18   if(argc > 1){
 19     JS_ToInt32(ctx, &button->val, argv[0]);
 20     button->name = JS_ToCString(ctx, argv[1]);
 21   }else if(argc > 0){
 22     JS_ToInt32(ctx, &button->val, argv[0]);
 23   }
 24   JSValue proto = JS_GetPropertyStr(ctx, val, "prototype");
 25   obj = JS_NewObjectProtoClass(ctx, JS_NULL, button_class_id);
 26   JS_SetPrototype(ctx, obj, proto);
 27   JS_FreeValue(ctx, proto);
 28   JS_SetOpaque(obj, button);
 29   return obj;
 30 }
 31 static void JSButtonFinalizer(JSRuntime *rt, JSValue val)
 32 {
 33   Button *button = (Button *)JS_GetOpaque(val, button_class_id);
 34   if(button){
 35     printf("\nfinalizer!\n");
 36   }
 37 }
 38 
 39 static JSClassDef button_class_def = {
 40   .class_name = "Button",
 41   .finalizer = JSButtonFinalizer,
 42 };
 43 static JSValue JSButtonGetVal(JSContext *ctx, JSValueConst this_val)
 44 {
 45   Button * button = (Button*)JS_GetOpaque2(ctx, this_val, button_class_id);
 46   if(button == NULL){
 47     return JS_EXCEPTION;
 48   }
 49   return JS_NewInt32(ctx, button->val);
 50 }
 51 static JSValue JSButtonSetVal(JSContext *ctx, JSValueConst this_val, JSValueConst val)
 52 {
 53   Button * button = (Button*)JS_GetOpaque2(ctx, this_val, button_class_id);
 54   if(button == NULL){
 55     return JS_EXCEPTION;
 56   }
 57   int v = 0;
 58   JS_ToInt32(ctx, &v, val);
 59   button->val = v;
 60   return JS_UNDEFINED;
 61 }
 62 static JSValue JSButtonGetName(JSContext *ctx, JSValueConst this_val)
 63 {
 64   Button * button = (Button*)JS_GetOpaque2(ctx, this_val, button_class_id);
 65   if(button == NULL){
 66     return JS_EXCEPTION;
 67   }
 68   return JS_NewString(ctx, button->name);
 69 }
 70 static JSValue JSButtonSetName(JSContext *ctx, JSValueConst this_val, JSValueConst val)
 71 {
 72   Button * button = (Button*)JS_GetOpaque2(ctx, this_val, button_class_id);
 73   if(button == NULL){
 74     return JS_EXCEPTION;
 75   }
 76   button->name = JS_ToCString(ctx, val);
 77   return JS_UNDEFINED;
 78 }
 79 static JSValue JSButtonTestFunc(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
 80 {
 81   Button * button = (Button*)JS_GetOpaque2(ctx, this_val, button_class_id);
 82   if(button == NULL){
 83     return JS_EXCEPTION;
 84   }
 85   if(argc > 0){
 86     button->name = JS_ToCString(ctx, argv[0]);
 87   }
 88   printf("test function1 called: argv=%s serid=%d\n", button->name, button->serid);
 89 }
 90 static JSValue JSButtonTestFunc2(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
 91 {
 92   printf("test function 22 called\n");
 93 }
 94 
 95 static const JSCFunctionListEntry button_class_funcs[] = {
 96   JS_CFUNC_DEF("testFunc", 0, JSButtonTestFunc),
 97   JS_PROP_INT32_DEF("serid", 1, JS_PROP_C_W_E),
 98   JS_CGETSET_DEF("name", JSButtonGetName, JSButtonSetName),
 99   JS_CGETSET_DEF("val", JSButtonGetVal, JSButtonSetVal)
100 };
101 static const JSCFunctionListEntry button_only_funcs[] = {
102   JS_CFUNC_DEF("testFunc2", 0, JSButtonTestFunc2),
103 };
104 
105 void ButtonClassInit(JSContext *ctx, JSModuleDef *m)
106 {
107   JS_NewClassID(&button_class_id);
108   JS_NewClass(JS_GetRuntime(ctx), button_class_id, &button_class_def);
109 
110   JSValue proto = JS_NewObject(ctx);
111   JS_SetPropertyFunctionList(ctx, proto, button_class_funcs, countof(button_class_funcs));  
112   
113   JSValue class = JS_NewCFunction2(ctx, JSButtonCreate, button_class_def.class_name, 1, JS_CFUNC_constructor, 0);
114   JS_SetConstructor(ctx, class, proto);
115   JS_SetClassProto(ctx, button_class_id, proto);
116   JS_SetModuleExport(ctx, m, button_class_def.class_name, class); //设置可导出类
117   JS_SetModuleExportList(ctx, m, button_only_funcs, countof(button_only_funcs)); //设置可导出函数
118 }
119 
120 int GuiModuleInit(JSContext *ctx, JSModuleDef *m)
121 {
122   ButtonClassInit(ctx, m);
123   //其他class初始化
124   return 0;
125 }
126 
127 int TestExportClassToJavaScript(JSContext *ctx)
128 {
129   JSModuleDef *m = JS_NewCModule(ctx, "Gui", GuiModuleInit);
130   if (!m)
131     return -1;
132 
133   JS_AddModuleExport(ctx, m, button_class_def.class_name); //导出类名
134   JS_AddModuleExport(ctx, m, "testFunc2"); //导出函数名
135 
136   char script[] = R"(
137     import {Button, testFunc2} from 'Gui';
138     import * as std from 'std';
139     std.printf("HELLO\n");
140     var tmp = new Button(1, "HI");
141     std.printf("val:" + tmp.val + " name:" + tmp.name + " serid:" + tmp.serid + "\n");
142     tmp.val = 123;
143     tmp.name = "WNZ";
144     tmp.serid = 123456789;
145     std.printf(tmp.val + "\n")
146     std.printf(tmp.name + "\n")
147     std.printf(tmp.serid + "\n")
148     tmp.cc = 111
149     std.printf(JSON.stringify(tmp) + "\n");
150     tmp.testFunc("a")
151     testFunc2()
152   )";
153   
154   JS_Eval(ctx, script, strlen(script), "<test>", JS_EVAL_TYPE_MODULE);
155   return 0;
156 }
157 
158 int main(int argc, char **argv)
159 {
160   JSRuntime *rt = JS_NewRuntime();
161   js_std_init_handlers(rt);;
162   JSContext *ctx = JS_NewContext(rt);
163   JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
164   js_std_add_helpers(ctx, -1, NULL);
165   js_init_module_os(ctx, "os");
166   js_init_module_std(ctx, "std");
167 
168   TestExportClassToJavaScript(ctx);
169   js_std_dump_error(ctx);
170   JS_FreeContext(ctx);
171   JS_FreeRuntime(rt);
172   return 0;
173 }

 

二、运行打印

 1 PS D:\test\quickjs\examples\byte> gcc .\main.c .\libquickjs.a  -I ..\..\ -o main ; .\main
 2 HELLO
 3 val:1 name:HI serid:1
 4 123
 5 WNZ
 6 123456789
 7 {"serid":123456789,"cc":111}
 8 test function1 called: argv=a serid=0
 9 test function 22 called
10 
11 finalizer!
12 null

 

三、代码简单讲解

  定义一个全局唯一的类ID(JSClassID)、js所需的类定义(JSClassDef)、类属性

 1 static JSClassID button_class_id;
 2 typedef struct _button
 3 {
 4   int val;
 5   const char *name;
 6   int serid;
 7 }Button;
 8 static JSClassDef button_class_def = {
 9   .class_name = "Button",
10   .finalizer = JSButtonFinalizer,
11 };

  定义类的构造函数、析构函数。注意、这里的finalizer析构函数,需要在定义button_class_def时就指定,不能在后面再指定,否则不执行。

 1 static JSValue JSButtonCreate(JSContext *ctx, JSValueConst val, int argc, JSValueConst *argv)
 2 {
 3   JSValue obj = JS_UNDEFINED;
 4   Button * button = (Button*)js_malloc(ctx, sizeof(Button));
 5   if(argc > 1){
 6     JS_ToInt32(ctx, &button->val, argv[0]);
 7     button->name = JS_ToCString(ctx, argv[1]);
 8   }else if(argc > 0){
 9     JS_ToInt32(ctx, &button->val, argv[0]);
10   }
11   JSValue proto = JS_GetPropertyStr(ctx, val, "prototype");
12   obj = JS_NewObjectProtoClass(ctx, JS_NULL, button_class_id);
13   JS_SetPrototype(ctx, obj, proto);
14   JS_FreeValue(ctx, proto);
15   JS_SetOpaque(obj, button);
16   return obj;
17 }
18 static void JSButtonFinalizer(JSRuntime *rt, JSValue val)
19 {
20   Button *button = (Button *)JS_GetOpaque(val, button_class_id);
21   if(button){
22     printf("\nfinalizer!\n");
23   }
24 }

  属性的两种定义方式、普通的属性JS_DEF_PROP_INT32、具有getset的属性JS_DEF_CGETSET。

  属性的绑定,还有类的创建和导出,这一部分会进行简写,使用框架自带的宏

 1 int ButtonClassInit(JSContext *ctx, JSModuleDef *m)
 2 {
 3   JS_NewClassID(&button_class_id);
 4   JS_NewClass(JS_GetRuntime(ctx), button_class_id, &button_class_def);
 5 
 6   JSValue proto = JS_NewObject(ctx);
 7   JSCFunctionListEntry entryList[3];
 8   entryList[0].name = "val";
 9   entryList[0].prop_flags = JS_PROP_CONFIGURABLE;
10   entryList[0].def_type = JS_DEF_CGETSET;
11   entryList[0].magic = 0;
12   entryList[0].u.getset.get.getter = JSButtonGetVal;
13   entryList[0].u.getset.set.setter = JSButtonSetVal;
14   entryList[1].name = "name";
15   entryList[1].prop_flags = JS_PROP_CONFIGURABLE;
16   entryList[1].def_type = JS_DEF_CGETSET;
17   entryList[1].magic = 0;
18   entryList[1].u.getset.get.getter = JSButtonGetName;
19   entryList[1].u.getset.set.setter = JSButtonSetName;
20   entryList[2].name = "serid";
21   entryList[2].prop_flags = JS_PROP_C_W_E;
22   entryList[2].def_type = JS_DEF_PROP_INT32;
23   entryList[2].magic = 0;
24   entryList[2].u.i32 = 999;
25   // button_class_def.finalizer = JSButtonFinalizer; //析构函数
26   JS_SetPropertyFunctionList(ctx, proto, entryList, 3);
27   JSValue class = JS_NewCFunction2(ctx, JSButtonCreate, button_class_def.class_name, 1, JS_CFUNC_constructor, 0);
28   JS_SetConstructor(ctx, class, proto);
29   JS_SetClassProto(ctx, button_class_id, proto);
30   JS_SetModuleExport(ctx, m, button_class_def.class_name, class);
31 }

  JS测试代码、 可以通过import{Button} from 'Gui' 导出某个模块中具体的类。如果是函数,可以通过 import {testFunc2} from 'Gui' 导出某个模块中的具体函数。还可以通过 import * as gui from 'Gui' 导出整个模块。

 1 int TestExportClassToJavaScript(JSContext *ctx)
 2 {
 3   JSModuleDef *m = JS_NewCModule(ctx, "Gui", GuiModuleInit);
 4   if (!m)
 5     return -1;
 6 
 7   JS_AddModuleExport(ctx, m, button_class_def.class_name);
 8 
 9   char script[] = R"(
10     import {Button} from 'Gui';
11     import * as std from 'std';
12     std.printf("HELLO\n");
13     var tmp = new Button(1, "HI");
14     std.printf("val:" + tmp.val + " name:" + tmp.name + " serid:" + tmp.serid + "\n");
15     tmp.val = 123;
16     tmp.name = "WNZ";
17     tmp.serid = 123456789;
18     std.printf(tmp.val + "\n")
19     std.printf(tmp.name + "\n")
20     std.printf(tmp.serid + "\n")
21     tmp.cc = 111
22     std.printf(JSON.stringify(tmp));
23   )";
24   
25   JS_Eval(ctx, script, strlen(script), "<test>", JS_EVAL_TYPE_MODULE);
26   return 0;
27 }

四、类的函数定义

  上面讲的是属性的定义、下面这个是函数的定义,方法其实跟之前博文中类似,只是之前是通过一个宏 JS_CFUNC_DEF 进行定义和绑定的。简写后如下

 1 static const JSCFunctionListEntry button_class_funcs[] = {
 2   JS_CFUNC_DEF("testFunc", 0, JSButtonTestFunc),
 3   JS_PROP_INT32_DEF("serid", 1, JS_PROP_C_W_E),
 4   JS_CGETSET_DEF("name", JSButtonGetName, JSButtonSetName),
 5   JS_CGETSET_DEF("val", JSButtonGetVal, JSButtonSetVal)
 6 };
 7 static const JSCFunctionListEntry button_only_funcs[] = {
 8   JS_CFUNC_DEF("testFunc2", 0, JSButtonTestFunc2),
 9 };
10 
11 void ButtonClassInit(JSContext *ctx, JSModuleDef *m)
12 {
13   JS_NewClassID(&button_class_id);
14   JS_NewClass(JS_GetRuntime(ctx), button_class_id, &button_class_def);
15 
16   JSValue proto = JS_NewObject(ctx);
17   JS_SetPropertyFunctionList(ctx, proto, button_class_funcs, countof(button_class_funcs));  
18   
19   JSValue class = JS_NewCFunction2(ctx, JSButtonCreate, button_class_def.class_name, 1, JS_CFUNC_constructor, 0);
20   JS_SetConstructor(ctx, class, proto);
21   JS_SetClassProto(ctx, button_class_id, proto);
22   JS_SetModuleExport(ctx, m, button_class_def.class_name, class); //设置可导出类
23   JS_SetModuleExportList(ctx, m, button_only_funcs, countof(button_only_funcs)); //设置可导出函数
24 }

 

 

 

参考资料:

  https://www.cnblogs.com/rpg3d/p/17278800.html

本文地址:https://www.cnblogs.com/wunaozai/p/17862838.html

系列目录:https://www.cnblogs.com/wunaozai/p/17853962.html

posted @ 2023-12-05 14:43  无脑仔的小明  阅读(110)  评论(0编辑  收藏  举报