在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
前言任何一家Saas企业都需要有自己的低代码平台.在可视化低代码的前端研发过程中, 发现了很多有意思的技术需求, 在解决这些需求的过程中, 往往也会给自己带来很多收获, 今天就来分享一下在研发Dooring过程中遇到的前端技术问题——javascript函数存储. 背景介绍我们都知道要想搭建一个前端页面基本需要如下3个要素:
在 数据驱动视图 的时代, 这三个要素的关系往往如下图所示: 可视化搭建平台的设计思路往往也是基于上面的过程展开的, 我们需要提供编辑器环境给用户来创建视图和交互, 最终用户保存的产物可能是这样的: { "name": "Dooring表单", "bgColor": "#666", "share_url": "http://xxx.cn", "mount_event": [ { "id": "123", "func": () => { // 初始化逻辑 GamepadHapticActuator(); }, "sourcedata": [] } ], "body": [ { "name": "header", "event": [ { "id": "123", "type": "click", "func": () => { // 组件自定义交互逻辑 showModal(); } } ] } ] } 那么问题来了, json 字符串我们好保存(可以通过JSON.stringify序列化的方式), 但是如何将函数也一起保存呢? 保存好了函数如何在页面渲染的时候能正常让 js 运行这个函数呢? 实现方案思考我们都知道将 js 对象转化为json 可以用 JSON.stringify 来实现, 但是它也会有局限性, 比如:
我们可以看到第4条, 如果我们序列化的对象中有函数, 它将会被忽略! 所以常理上我们使用JSON.stringify 是无法保存函数的, 那还有其他办法吗? 也许大家会想到先将函数转换成字符串, 再用 JSON.stringify 序列化后保存到后端, 最后在组件使用的时候再用 eval 或者 Function 将字符串转换成函数. 大致流程如下: 不错, 理想很美好, 但是现实很_______. 接下来我们就一起分析一下关键环节 func2string 和 string2func 如何实现的. js存储函数方案设计熟悉 JSON API 的朋友可能会知道 JSON.stringify 支持3个参数, 第二个参数 replacer 可以是一个函数或者一个数组。作为函数,它有两个参数,键(key)和值(value),它们都会被序列化。 函数需要返回 JSON 字符串中的 value, 如下所示:
所以我们可以在第二个函数参数里对 value类型为函数的数据进行转换。如下: const stringify = (obj) => { return JSON.stringify(obj, (k, v) => { if(typeof v === 'function') { return `${v}` } return v }) } 这样我们看似就能把函数保存到后端了. 接下来我们看看如何反序列化带函数字符串的 json. 因为我们将函数转换为字符串了, 我们在反解析时就需要知道哪些字符串是需要转换成函数的, 如果不对函数做任何处理我们可能需要人肉识别.
所以我换了一种简单的方式, 可以不用写复杂正则就能将函数提取出来, 方法就是在函数序列化的时候注入标识符, 这样我们就能知道那些字符串是需要解析为函数了, 如下: stringify: function(obj: any, space: number | string, error: (err: Error | unknown) => {}) { try { return JSON.stringify(obj, (k, v) => { if(typeof v === 'function') { return `${this.FUNC_PREFIX}${v}` } return v }, space) } catch(err) { error && error(err) } } this.FUNC_PREFIX 就是我们定义的标识符, 这样我们在用 JSON.parse 的时候就能快速解析函数了. JSON.parse 也支持第二个参数, 他的用法和 JSON.stringify 的第二个参数类似, 我们可以对它进行转换, 如下: parse: function(jsonStr: string, error: (err: Error | unknown) => {}) { try { return JSON.parse(jsonStr, (key, value) => { if(value && typeof value === 'string') { return value.indexOf(this.FUNC_PREFIX) > -1 ? new Function(`return ${value.replace(this.FUNC_PREFIX, '')}`)() : value } return value }) } catch(err) { error && error(err) } } new Function 可以把字符串转换成 js 函数, 它只接受字符串参数,其可选参数为方法的入参,必填参数为方法体内容, 一个形象的例子: 我们上述的代码中函数体的内容: new Function(`return ${value.replace(this.FUNC_PREFIX, '')}`)() 之所以要 return 是为了把原函数原封不动的还原, 大家也可以用 eval , 但是出于舆论还是谨慎使用. 以上方案已经能实现前端存储函数的功能了, 但是为了更工程化和健壮性还需要做很多额外的处理和优化, 这样才能让更多人开箱即用的使用你的库. 最后为了让更多人能直接使用这个功能, 我将完整版 json 序列化方案封装成了类库, 支持功能如下:
安装方式如下: # or npm install xijs yarn add xijs 使用: import { parser } from 'xijs'; const a = { x: 12, b: function() { alert(1) } } const json = parser.stringify(a); const obj = parser.parse(json); // 调用方法 obj.b(); 总结到此这篇关于利用javascript存储函数的文章就介绍到这了,更多相关用javascript存储函数内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论