请慎用 eval 函数

370 阅读4分钟

image.png

如上图,为了公式编辑器中的组件相互的一个计算,但由于计算公式的不确定性,以及计算公式我们保存的是一个字符串,实现该功能时,我在网上查了许多方式,以及寻找到了解析公式计算后参与计算的方式,但在后续测试中,发现该公式存在着极大的缺陷,以及许多不确定性,于是我便想着有没有什么更加简单,更加方便的方法。就在我满头问号的时候,我找到该方法,就是eval 函数。

后来在我的项目中,便将该方法安排在我项目中,但我们公司的前端大佬,发现这个函数,后对我说,这个方法好像在mdn中不推荐使用,于是我就查查了该函数,以及寻找该函数的有没有什么替代方案。于是便查找了下面有关内容

功能

mdn: developer.mozilla.org/zh-CN/docs/…

大家可以在这个链接中了解这个函数,我这边先简单介绍一下。

eval 函数会将传入的字符串当成函数来执行, 但字符串传参不同,返回的结果也是不同的,具体的如下几种情况

  1. 传入 数学计算公式,会直接返回计算结果
  2. 传入 js语句, 会将里面的js语句会直接执行
  3. 传入非字符串,会直接将里面的返回
// 数学计算公式 返回 3
console.log(eval('1 + 2'))
// js 语句 返回 String(2 + 2)
console.log(eval("new String('1 + 2')"))
// 非字符串 返回 3
console.log(eval(3))

同时eval 函数也会因为调用方式不同,也会产生不同的情况,

  1. 直接调用 ,如果是在自己本身的作用域里面,直接调用,在eval函数里面就可以访问函数里面定义的参数
  2. 间接调用。如果是间接调用,那么会访问全局作用域而不是自己的作用域下面

如下例子

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 看了一下情况

  1. eval 函数不安全,容易被恶意攻击
  2. 性能不行,因为在使用eval 函数的时候,它会让浏览器调用js解释器 , 在mdn上查找说是性能问题,但在我实际测试中,发现, eval函数调用时内存占比5.1MB,但替代方案占比是7.3MB

替代方案: Function

后来我就看了有没有类似于替代eval函数的方式,在mdn发现其实我一直都在忽视的一个属性Function, 虽然我们一直都在使用,其实都没有去深入的了解过,直到我突然发现,他也能将字符串当成函数解析。让我感觉这个Function也比较的强大啊

下面我讲述他的优点,

  1. 相比于eval 函数,他更加的安全
  2. 它可以使用use strict 修饰词, 比eval 函数会更加的严格,
  3. 使用Function 不需要关注他的作用域的问题.他访问变量基本都是全局变量

疑问

但在我测试中也发现了一点就是在mdn上讲解eval 函数性能差,但在我实际测试中,与Function 函数进行比较,发现该eval 函数的占用内存比要比Function 函数低有没有大佬给我讲解一下

总结

在我查找,eval 函数的时候, 感觉这个函数的功能十分强大,但实际使用中,发现其的注意事项还是比价多的,一个就是 要时刻注意eval函数使用中的作用域以及其容易被攻击的情况. 相比于eval 函数的 Function 函数就不需要但其作用域问题. 无论间接调用和直接调用他访问的变量都是全局变量. 这个时候如果想要作用域下面的代码,其实这边可以直接写js代码就好了, 不需要使用 这两个函数, 感觉这样 性能会做的更好.

当然, 不管eval函数的功能在如何的强大, 既然人家都说不要使用, 我们就要听不是吗, 反正eval函数不是有许多的替代方案吗