前端进阶: 奈何用 Javascript 存储函数?
发布日期:2022-06-18 17:09 点击次数:105任何一家Saas企业都需要有我方的低代码平台.在可视化低代码的前端研发过程中, 发现了许多有真义的本领需求, 在管制这些需求的过程中, 每每也会给我方带来许多得益, 今天就来共享一下在研发Dooring过程中遭受的前端本领问题——javascript函数存储.
配景先容咱们都暴露要想搭建一个前端页面基本需要如下3个身分:
元素(UI) 数据(Data) 事件/交互(Event)在 数据驱动视图 的时间, 这三个身分的相干每每如下图所示:
趣谈前端
可视化搭建平台的打算端倪每每亦然基于上头的过程伸开的, 咱们需要提供剪辑器环境给用户来创建视图和交互, 最终用户保存的居品可能是这么的:
{ "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 来已毕, 然则它也会有局限性, 比如:
退换值若是有 toJSON() 循序,那么由 toJson() 界说什么值将被序列化 非数组对象的属性不可保证以特定的端正出刻下序列化后的字符串中 布尔值、数字、字符串的包装对象在序列化过程中会自动退换成对应的原始值 undefined、自便的函数以及 symbol 值,在序列化过程中会被忽略(出刻下非数组对象的属性值中时)大略被退换成 null(出刻下数组中时)。函数、undefined 被单独退换时,会复返 undefined,如JSON.stringify(function(){}) or JSON.stringify(undefined) 扫数以 symbol 为属性键的属性都会被完美忽略掉,即便 replacer 参数中强制指定包含了它们 Date 日历调用了 toJSON() 将其退换为了 string 字符串(同Date.toISOString()),因此会被当做字符串处理 NaN 和 Infinity 体式的数值及 null 都会被当做 null 其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可胪列的属性咱们可以看到第4条, 若是咱们序列化的对象中有函数, 免费看小12萝裸体视频国产 它将会被忽略! 是以常理上咱们使用JSON.stringify 是无法保存函数的, 那还有其他方针吗?
也许人人会预见先将函数退换成字符串, 再用 JSON.stringify 序列化后保存到后端, 终末在组件使用的时间再用 eval 大略 Function 将字符串退换成函数. 约莫经由如下:
趣谈前端
可以, 期望很美好, 然则履行很_______.
接下来咱们就通盘分析一下关节要领 func2string 和 string2func 奈何已毕的.
js存储函数决议打算老练 JSON API 的知心可能会暴露 JSON.stringify 搭救3个参数, 第二个参数 replacer 可以是一个函数大略一个数组。算作函数,它有两个参数,键(key)和值(value),它们都会被序列化。 函数需要复返 JSON 字符串中的 value, 如下所示:
若是复返一个 Number, 退换成相应的字符串算作属性值被添加入 JSON 字符串
若是复返一个 String, 该字符串算作属性值被添加入 JSON 字符串
若是复返一个 Boolean, 则 "true" 大略 "false" 算作属性值被添加入 JSON 字符串
若是复返任何其他对象,该对象递归地序列化成 JSON 字符串,被按摩师玩弄到潮喷在线播放对每个属性调用 replacer 循序。除非该对象是一个函数,这种情况将不会被序列化成 JSON 字符
若是复返 undefined,该属性值不会在 JSON 字符串中输出
是以咱们可以在第二个函数参数里对 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 序列化决议封装成了类库, 搭救功能如下:
stringify 在原生JSON.stringify 的基础上搭救序列化函数,无理回调
parse 在原生JSON.parse 的基础上搭救反序列化函数,无理回调
funcParse 将js对象中的函数一键序列化, 并保持js对象类型不变
装配神气如下:
# 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();
本文转载自微信公众号「趣谈前端」,可以通过以下二维码存眷。转载本文请有关趣谈前端公众号。