接口突然返回字符串,eval派上用场了
1、背景
在请求某个文件时,正常情况下接口会返回json
对象,但是这个比较特殊,竟然返回json
字符串
大概率是因为数据量太大,接口自动转化为字符串来传输
心想,这也简单,判断一下类型,是字符串就将其转化为json
对象即可
if (typeof data === 'string') {
data = JSON.parse(data)
}
然后就报错了:
大概意思就是json
字符串中存在非法字符,使用JSON.parse()
解析就报错了
JSON.parse()
只能解析标准的JSON
字符串
可是24M
的数据,哪里知道是出现了有哪些非法字符
google
了一下,发现eval
也有将字符串转化为对象的功能,过程也很简单
if (typeof data === 'string') {
data = eval("(" + data + ")")
}
好了 问题解决了
2、eval
究竟是啥
MDN上的介绍:eval()
会将传入的字符串转化成js
代码进行执行
eval(String)
参数:
- 如果传入
String
,会转化为js
进行执行 - 如果传入非
String
,直接返回该值
返回值:
- 字符串的执行结果
- 如果执行结果为空,则返回
undefined
小试一下:
eval('1+1') // 2
eval(new String('1')) // String {'1'}
eval({}) // {}
2.1 为啥需要加上括号eval('(' + data + ')')
先看一下直接传入对象字符串是怎么样的
eval('{}') // undefined
!! 居然是一个undefined
这是因为当'{}'
被转成js
代码后,{}
会被当成一个语句来执行,其执行结果为空,所以也就返回了undefined
在js
中,用()
将一个语句括起来,那么语句就变成表达式了
let a = 1
const falg = true
if (flag) {
a = 2
}
这是一个很简单的逻辑,但是写法还是有点繁琐了,可以用&&
代替这个if
语句
flag && (a = 2)
因为&&
后面必须跟表达式而不能是语句,所以用()
将a=2
赋值语句转化为表达式即可
同样道理,既然eval('{}')
会将 {}
当成语句来执行,那就给它拼接上 ()
,让它变成一个表达式, eval
将其转化为js
代码后就会解析成对象了
eval('({})') // {}
// 区别于
eval('{}') // undefined
eval({}) // {},为什么eval({})又会返回{},因为它不是字符串 会直接返回其本身
2.2 永远不要使用eval
eval
存在两个原因,让我们不推荐使用它:
- 不安全
- 性能问题
不安全
所谓的不安全就是容易被脚本注入
eval
拥有执行代码的权力,如果我们的字符串被替换成了一段恶意的代码,攻击者就可以在我们电脑上运行恶意代码了
eval("alert('我是恶意代码')")
性能问题
eval
会调用js
解析器,会进行冗余的变量名查找、确定位置、设置值等一系列操作
另外,新内容将会通过 eval() 引进给变量,比如更改该变量的类型,因此会强制浏览器重新执行所有已经生成的机器代码以进行补偿
2.3 使用Function
代替eval
鉴于eval()
不安全和性能问题,有一个很好的方法可以代替eval
new Function()
它和eval
一样,可以对无效的json
对象进行转化
const str = "{name:'zxc',age:18}"
new Function('return' + str)() // {name: 'zxc',age: 18}
几点区别:
// 转化json字符串
new Function('return' + '{}')() // {}
// 转化array字符串
new Function('return' + '[1, 2]')() // [1, 2]
// 转化function字符串
new Function("return function foo() { console.log(123)}")()() // 123
// 转化对象
new Function('return' + {})() // error: Unexpected identifier 'Object'
// 转化字符串
new Function('return' + '1+1')() // error: return1 is not defined
new Function()
只能接受对象字符串- 不需要使用括号
()
进行转义
3、总结
一、现在知道了,字符串转化为对象有3种方式:
JSON.parse(strJSON)
只能转化标准的
JSON
字符串(键必须是字符串,字符串必须使用双引号括起来)
eval(str)
- 将字符串转化为
js
语句,并执行- 如果不希望转化后是
js
语句,可使用括号将字符串包裹起来
Function(str)()
只能转化对象字符串
二、非必要不适用eval
,尽量使用Function
代替
三、转化标准json
字符串使用JSON.parse()
,非标使用Function
转载自:https://juejin.cn/post/7184747940957651005