网易首页 > 网易号 > 正文 申请入驻

前端进阶: 如何用 Javascript 存储函数?

0
分享至

作者: 徐小夕 来源: 趣谈前端

任何一家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条, 如果我们序列化的对象中有函数, 它将会被忽略! 所以常理上我们使用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();

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
王楚钦为何逆转松岛夺冠!赛后说出大实话,邓亚萍点评一针见血

王楚钦为何逆转松岛夺冠!赛后说出大实话,邓亚萍点评一针见血

小徐讲八卦
2026-04-06 05:07:16
美论坛:为什么中国在明确我们不会偿还的情况下还要购买美债?

美论坛:为什么中国在明确我们不会偿还的情况下还要购买美债?

闻识
2026-04-05 23:12:22
美媒:中国应对中东危机展现惊人韧性

美媒:中国应对中东危机展现惊人韧性

参考消息
2026-04-06 16:28:04
阿根廷国脚、热刺队长合同泄密!亲爹爆料解约金:7000万美元!

阿根廷国脚、热刺队长合同泄密!亲爹爆料解约金:7000万美元!

仰卧撑FTUer
2026-04-06 20:19:04
恩爱剧本不演了?奚梦瑶提离婚,何猷君掀桌子私生子传闻真相大白

恩爱剧本不演了?奚梦瑶提离婚,何猷君掀桌子私生子传闻真相大白

秋姐居
2026-04-04 22:23:29
6岁女童走失后续:有新发现 奶茶店主做出回应,可疑人浮出水面!

6岁女童走失后续:有新发现 奶茶店主做出回应,可疑人浮出水面!

普陀动物世界
2026-04-06 18:42:33
火箭取得本季最长连胜!火记:6连胜是最佳表现 关键时刻终于赢球

火箭取得本季最长连胜!火记:6连胜是最佳表现 关键时刻终于赢球

Emily说个球
2026-04-06 14:10:41
大家一定要做好心理准备,周边的局势已经越来越紧张了

大家一定要做好心理准备,周边的局势已经越来越紧张了

安安说
2026-04-05 11:23:47
南京博物院事件真相来了:果然,那些人真狗啊!

南京博物院事件真相来了:果然,那些人真狗啊!

李月亮
2026-02-10 20:58:01
不装阔不套近乎!李亚鹏喊话张雪:钱现在掏不出,但兄弟我拉群

不装阔不套近乎!李亚鹏喊话张雪:钱现在掏不出,但兄弟我拉群

阿讯说天下
2026-04-06 10:56:01
美军跳伞飞行员身背“小金库”,步枪金条电台一应俱全,非常难捉

美军跳伞飞行员身背“小金库”,步枪金条电台一应俱全,非常难捉

利刃号
2026-04-05 23:38:07
潜伏在中国的反华家族,靠大陆收入上亿,今国家出手下场大快人心

潜伏在中国的反华家族,靠大陆收入上亿,今国家出手下场大快人心

混沌录
2026-04-05 16:33:20
1969年,教员为什么对贺帅不满?二人之间到底有何分歧?

1969年,教员为什么对贺帅不满?二人之间到底有何分歧?

阿胡
2025-02-23 13:09:21
新中国成立后,清政府遗留7.3亿两白银烂账,主席一招便成功化解

新中国成立后,清政府遗留7.3亿两白银烂账,主席一招便成功化解

唠叨说历史
2026-01-07 14:51:34
年度最佳,这部9分科幻美剧值得一看

年度最佳,这部9分科幻美剧值得一看

来看美剧
2026-04-06 19:56:20
突发!8.4万散户假期踩雷:两家财务造假公司下周被ST,两家直接退市

突发!8.4万散户假期踩雷:两家财务造假公司下周被ST,两家直接退市

股市皆大事
2026-04-06 10:47:12
2026年985大学排名变了:浙大并列第3,南大第7,哈工大跌至第10

2026年985大学排名变了:浙大并列第3,南大第7,哈工大跌至第10

Delete丨CC
2026-04-06 12:49:50
奇兵5记三分,山东男篮大胜广东,高诗岩15+6点名徐杰 争三占先机

奇兵5记三分,山东男篮大胜广东,高诗岩15+6点名徐杰 争三占先机

替补席看球
2026-04-06 21:35:55
法媒:海湾国家军事实力几何?

法媒:海湾国家军事实力几何?

参考消息
2026-04-05 20:04:08
国务院831号令:6月1日起统一执行!家家户户用水将迎7大变化

国务院831号令:6月1日起统一执行!家家户户用水将迎7大变化

小影的娱乐
2026-04-06 18:34:51
2026-04-06 22:12:49
Nodejs开发
Nodejs开发
分享只有程序员懂的干货
648文章数 823关注度
往期回顾 全部

科技要闻

折叠屏iPhone要来了,富士康已在试产!

头条要闻

特朗普咆哮式发帖威胁伊朗 美政界人士:他像精神错乱

头条要闻

特朗普咆哮式发帖威胁伊朗 美政界人士:他像精神错乱

体育要闻

球员系列赛大满贯!赵心童10-3世界第一 加冕赛季第4冠

娱乐要闻

唐嫣罗晋新加坡遛娃,6岁女儿身高抢镜

财经要闻

史诗级暴跌"一周年" A股接下来如何走?

汽车要闻

阿维塔06T快上市了 旅行车还能这么玩?

态度原创

本地
家居
教育
手机
健康

本地新闻

跟着歌声游安徽,听古村回响

家居要闻

温馨多元 爱的具象化

教育要闻

江苏春假刚结束,全省中小学2026年秋假时间表已火速敲定。各中小学在10月至11月期间可自主安排为期...

手机要闻

何刚公布华为折叠屏限时购机权益,含1年HUAWEI Care+等

干细胞抗衰4大误区,90%的人都中招

无障碍浏览 进入关怀版