前端 json-bigint 的问题分析

相关工具

问题描述

一个详情弹窗组件,首次打开显示正常,关掉后再打开,表单值会丢失
1-1

排查思路

该组件默认会在关闭时有清空表单项,内部也会监听数据的变动,理论上应该可以正常展示
在这里插入图片描述
在监听的地方打断点,可以看到能正常走进来,但是因为 newV instanceof Objectfalse ,数据不能被正常赋值,所以页面会显示空白,沿着调用栈往上走一级看看
在这里插入图片描述
可以看到 vue 内也有 isObject 的判断方法,考虑到这两个地方的目的类似,便把组件内的判断也改成了 vue 的方式,修改后表单在多次打开时也能正常显示了,而 newV instanceof Object === false 的根源暂时没有再追究
在这里插入图片描述
几天之后,空闲时间又回想起来上面的 false 问题,先是拿 vue 的 watch 验证,写一个简单的空对象 {} ,再修改值后打印结果,正常为 true ,说明没问题,
又想到这个数据是从接口返回的,就拿 JSON.parse 解析一个简单的 json 字符串验证,结果也正常为 true ,也没问题,
但是表格的 tableConfig.data 里,每一项的求值确实都是 false
在这里插入图片描述

最后重新回顾数据从接口字符串解析成对象的过程,发现还经过了 json-bigint 处理(这个库是为了解决三方接口里的id数字过大问题引入),
这个库在解析 object 类型的时候,使用了 Object.create(null)
在这里插入图片描述
而使用这种方式创建的对象和普通对象会有些差别(如下图)
在这里插入图片描述
原型信息的丢失,让上面的 instanceOf 判断失效了,关于原型链及对象创建的相关概念,可以看看《JavaScript高级程序设计》等书;
到这一步,算是找到了 false 的原因,另外在 vue 源码搜一下,也能看到这种写法,网上有关于这种写法的一些讨论,大家也可以自行了解下

另一种场景

本地开发环境 配置 app 菜单权限时,还碰到一个异常,这个异常会导致弹窗组件渲染失败
在这里插入图片描述
可以通过异常断点功能,继续追查一下
在这里插入图片描述
这里组件希望 data 的值为一个 Object ,但实际传入的却是一个 Array

function styleValue (value, type) {
  if (type === 'String') {
    return ("\"" + value + "\"")
  } else if (type === 'Number') {
    return ("" + (Number(value)))
  } else {
    return ("" + value)
  }
}

当 vue 想通过上面这个转换方法,提示用户数据格式有问题时,就发生了上面图里的 TypeError
这个传入的 Array 数据,由后台接口返回,其内部是一个 Object 对象,也通过 Object.create(null) 创建,
使用 Object.create(null) + '' 可以简单验证下,会发生一样的异常

考虑到项目中这种情况可能较多,最后把 json-bigint 源码复制到项目中,把 object=Object.create(null) 直接修改成了 object={}

延伸思考

像上面这种出异常的代码,也算是比较常见的写法了,
所以也比较好奇,库的作者为什么要使用这种写法来创建对象,随后便找到了这样的说明: https://github.com/sidorares/json-bigint/issues/38
在这里插入图片描述
这里提到了一个原型污染的概念(prototype pollution),能看到作者大概也是为了修复漏洞,所以换成了上面的写法(代码库里也有相应的git提交记录)

这里简单贴两篇介绍:

Prototype Pollution
深入理解 JavaScript Prototype 污染攻击

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值