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
作者:无脑仔的小明 出处:http://www.cnblogs.com/wunaozai/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 如果文中有什么错误,欢迎指出。以免更多的人被误导。有需要沟通的,可以站内私信,文章留言,或者关注“无脑仔的小明”公众号私信我。一定尽力回答。 |