如上图,为了公式编辑器中的组件相互的一个计算,但由于计算公式的不确定性,以及计算公式我们保存的是一个字符串,实现该功能时,我在网上查了许多方式,以及寻找到了解析公式计算后参与计算的方式,但在后续测试中,发现该公式存在着极大的缺陷,以及许多不确定性,于是我便想着有没有什么更加简单,更加方便的方法。就在我满头问号的时候,我找到该方法,就是eval 函数。
后来在我的项目中,便将该方法安排在我项目中,但我们公司的前端大佬,发现这个函数,后对我说,这个方法好像在mdn中不推荐使用,于是我就查查了该函数,以及寻找该函数的有没有什么替代方案。于是便查找了下面有关内容
功能
mdn: developer.mozilla.org/zh-CN/docs/…
大家可以在这个链接中了解这个函数,我这边先简单介绍一下。
eval 函数会将传入的字符串当成函数来执行, 但字符串传参不同,返回的结果也是不同的,具体的如下几种情况
- 传入 数学计算公式,会直接返回计算结果
- 传入 js语句, 会将里面的js语句会直接执行
- 传入非字符串,会直接将里面的返回
// 数学计算公式 返回 3
console.log(eval('1 + 2'))
// js 语句 返回 String(2 + 2)
console.log(eval("new String('1 + 2')"))
// 非字符串 返回 3
console.log(eval(3))
同时eval 函数也会因为调用方式不同,也会产生不同的情况,
- 直接调用 ,如果是在自己本身的作用域里面,直接调用,在eval函数里面就可以访问函数里面定义的参数
- 间接调用。如果是间接调用,那么会访问全局作用域而不是自己的作用域下面
如下例子
let x = 2
let y = 3
// 结果 5
console.log(eval('x + y')) // 全局访问
test()
// 函数作用域
function test() {
let x = 3
let y = 4
// 结果: 7
console.log('eval:', eval('x + y')) // 直接调用
let geval = eval
// 结果: 5
console.log('geval:',geval('x + y')) // 间接调用
}
// 块级作用域
var flag = true
if (flag) {
let x = 4
let y = 5
// 结果: 9
console.log('块级作用域 eval:', eval('x + y')) // 直接调用
let geval = eval
// 结果: 5
console.log('geval:',geval('x + y')) // 间接调用
}
缺陷
在我测试过程中,发现eval 的功能可以是强大的,但后来在杜老大说这个的参数是不推荐使用的,我就去了mdn 看了一下情况
- eval 函数不安全,容易被恶意攻击
- 性能不行,因为在使用eval 函数的时候,它会让浏览器调用js解释器 , 在mdn上查找说是性能问题,但在我实际测试中,发现, eval函数调用时内存占比5.1MB,但替代方案占比是7.3MB
替代方案: Function
后来我就看了有没有类似于替代eval函数的方式,在mdn发现其实我一直都在忽视的一个属性Function, 虽然我们一直都在使用,其实都没有去深入的了解过,直到我突然发现,他也能将字符串当成函数解析。让我感觉这个Function也比较的强大啊
下面我讲述他的优点,
- 相比于eval 函数,他更加的安全
- 它可以使用use strict 修饰词, 比eval 函数会更加的严格,
- 使用Function 不需要关注他的作用域的问题.他访问变量基本都是全局变量
疑问
但在我测试中也发现了一点就是在mdn上讲解eval 函数性能差,但在我实际测试中,与Function 函数进行比较,发现该eval 函数的占用内存比要比Function 函数低有没有大佬给我讲解一下
总结
在我查找,eval 函数的时候, 感觉这个函数的功能十分强大,但实际使用中,发现其的注意事项还是比价多的,一个就是 要时刻注意eval函数使用中的作用域以及其容易被攻击的情况. 相比于eval 函数的 Function 函数就不需要但其作用域问题. 无论间接调用和直接调用他访问的变量都是全局变量. 这个时候如果想要作用域下面的代码,其实这边可以直接写js代码就好了, 不需要使用 这两个函数, 感觉这样 性能会做的更好.
当然, 不管eval函数的功能在如何的强大, 既然人家都说不要使用, 我们就要听不是吗, 反正eval函数不是有许多的替代方案吗