什么是eval()?

eval()函数就是一个完整的 ECMAScript 解释器,它接收一个参数,即一个要执行的 ECMAScript(JavaScript)字符串。

与很多解释型语言一样,JavaScript有能力解释JavaScript源代码字符串,对它们求值以产生一个值。JavaScript就是通过全局函数eval()来对源代码字符串求值的。

关于eval()是函数还是操作符?

eval()是一个函数,其实应该是个操作符。JavaScript语言最初的版本定义了一个eval()函数,语言设计者和解释器开发者一直对它加以限制,导致它越来越像操作符。

现代JavaScript解释器会执行大量代码分析和优化。一般来说,如果一个函数调用eval(),则解释器将无法再优化该函数。

把eval()定义为函数的问题在于可以给它起不同的名字如果可以这样,那么解释器无法确定哪个函数会调用eval(),也就无法激进优化。假如eval()是个操作符(即保留字),那这个问题就可以避免。

作用域问题

通过 eval()执行的代码属于该调用所在上下文,被执行的代码与该上下文拥有相同的作用域链。

在执行 eval(..) 之后的代码时,引擎并不“知道”或“在意”前面的代码是以动态形式插入进来,并对词法作用域的环境进行修改的。引擎只会如往常地进行词法作用域查找。

eval()的使用

关于参数

eval()期待一个参数。

1.如果给它传入任何非字符串值,它会简单地返回这个值。

2.如果传入字符串,它会尝试把这个字符串当成JavaScript代码来解析,

①解析失败会抛出SyntaxError。

②如果最后一个表达式或语句没有值则返回undefined。

③如果解析字符串成功,它会求值代码并返回该字符串中最后一个表达式或语句的值。

④如果求值字符串抛出异常,该异常会从调用eval()的地方传播出来。

直接eval()

对于eval()(在像这样调用时),关键在于它会使用调用它的代码的变量环境。它会像本地代码一样查找变量的值、定义新变量和函数。

  1. 定义在包含上下文中的变量可以在 eval()调用内部被引用

如果一个函数定义了一个局部变量x,然后调用了eval("x"),那它会取得这个局部变量的值。

function foo() {    let x = 1 + 1;    eval("console.log(x)"); // 2}foo()
  1. 声明局部变量

如果这个函数调用了eval("var y = 3;"),则会声明一个新局部变量y。

eval("var y = '3';"); console.log(y); // 3

eval()声明一个局部函数

eval(`function foo() {    let x = 1 + 1;    console.log(x);}`)foo()
  1. 如果被求值的字符串使用了letconst,则声明的变量或常量会被限制在求值的局部作用域内,不会定义到调用环境中。

    通过 eval()定义的任何变量和函数都不会被提升,这是因为在解析代码的时候,它们是被包含在一个字符串中的。它们只是在 eval()执行的时候才会被创建。

eval("var msg = 'hello world';"); console.log(msg); // hello world

eval("let msg = 'hello world';"); console.log(msg); // Reference Error: msg is not defined
  1. 传给eval()的代码字符串本身必须从语法上说得通:不能使用它向函数中粘贴代码片段。

eval("return;")是没有意义的,因为return只在函数中是合法的,即使被求值的字符串使用与调用函数相同的变量环境,这个字符串也不会成为函数的一部分。

只要这个字符串本身可以作为独立的脚本运行(即使像x=0这么短),都可以合法地传给eval()。否则,eval()将抛出SyntaxError。

严格模式

一、严格模式对eval()函数增加了更多限制,甚至对标识符“eval”的使用也进行了限制。

当我们在严格模式下调用eval()时,或者当被求值的代码字符串以“use strict”指令开头时,eval(..) 在运行时有其自己的词法作用域,eval()会基于一个私有变量环境进行局部求值。这意味着在严格模式下,被求值的代码可以查询和设置局部变量,但不能在局部作用域中定义新变量或函数也就是说在 eval()内部创建的变量和函数无法被外部访问。

function foo(str) {    "use strict";    eval(str);    console.log(a); // ReferenceError: a is not defined}foo("var a = 2");

二、严格模式让eval()变得更像操作符,因为“eval”在严格模式下会变成保留字。

不能再使用新值来重写eval()函数。通过名字“eval”来声明变量、函数、函数参数或捕获块参数都是不允许的。

全局eval()

一、

eval()会干扰JavaScript的优化程序,是因为它能够修改局部变量。解释器也不会过多优化调用eval()的函数。

JavaScript规范中说,如果eval()被以“eval”之外的其他名字调用时,它应该把字符串当成顶级全局代码来求值。

被求值的代码可能定义新全局变量或全局函数,可能修改全局变量,但它不会再使用或修改调用函数的局部变量。因此也就不会妨碍局部优化。

使用名字“eval”来调用eval()函数就叫作“直接eval”(这样就有点保留字的感觉了)。直接调用eval()使用的是调用上下文的变量环境。如果在顶级代码中调用eval(),则它操作的一定是全局变量和全局函数。

二、

任何其他调用方式,包括间接调用,都使用全局对象作为变量环境,因而不能读、写或定义局部变量或函数(无论直接调用还是间接调用都只能通过var来定义新变量。在被求值的字符串中使用let和const创建的变量和常量会被限定在求值的局部作用域内,不会修改调用或全局环境)。

let x = 'g';let y = 'g';let gEval = eval;function g() {    let x = 'l';    gEval("x += 'changed'");    return x;}

function l() {    let y = 'l';    eval("y += 'changed'");    return y;}

console.log(g() , x); // l gchanged  g函数外部x改变了console.log(l() , y); // lchanged g  l函数内部y改变了

这种全局求值的能力不仅仅是为了适应优化程序的需求,同时也是一种极其有用的特性,可以让我们把代码字符串作为独立、顶级的脚本来执行。假如你必须使用eval(),那很可能应该使用它的全局求值而不是局部求值。

为什么不提倡使用eval()?

解释代码字符串的能力是非常强大的,但也非常危险。在使用 eval()的时候必须极为慎重,特别是在解释用户输入的内容时。因为这个方法会对 XSS 利用暴露出很大的攻击面。恶意用户可能插入会导致你网站或应用崩溃的代码。

某些Web服务器使用HTTP的"Content-Security-Policy"头部对整个网站禁用eval()

无论在声明时候eval()都可以运行期间修改书写期的词法作用域。除了严格模式。

和eavl函数有类似作用

setTimeout(..) 和 setInterval(..) 的第一个参数可以是字符串,字符串的内容可以被解释为一段动态生成的函数代码。这些功能已经过时且并不被提倡。不要使用它们!

new Function(..) 函数的行为也很类似,最后一个参数可以接受代码字符串,并将其转化为动态生成的函数(前面的参数是这个新生成的函数的形参)。这种构建函数的语法比 eval(..) 略微安全一些,但也要尽量避免使用。

在程序中动态生成代码的使用场景非常罕见,因为它所带来的好处无法抵消性能上的损失。

参考

《你不知道的js上》 《JavaScript权威指南第七版》 《JavaScript高级程序设计第四版》

本文由 mdnice 多平台发布

万恶的 eval() ?相关推荐

  1. 建议使用更加安全的ast.literal_eval去替代eval

    前言 如果大家想要在python中将字符串转换成列表,数字,字典等操作,都会想到使用eval(),确实这个函数很好用,但是它却存在一定的安全性 eval的漏洞 如果用户使用如下的代码 open(r'D ...

  2. shell eval命令

    1. eval command-line 其中command-line是在终端上键入的一条普通命令行.然而当在它前面放上eval时,其结果是shell在执行命令行之前扫描它两次.如: pipe=&qu ...

  3. AngularJS $eval $parse

    $eval $parse都可以解析或计算Angular表达式的值. 一.$parse 是一个独立的可以注入的服务,注入就可以使用,它返回一个函数,我们需要显式将表达式求值的上下文传递给该函数.$par ...

  4. 微信小程序开发之不能使用eval函数的问题

    2019独角兽企业重金招聘Python工程师标准>>> 一 eval函数问题 JavaScript中的eval函数是颇受开发者争议的问题之一,问题主要在于其可能导致的不安全性.有关此 ...

  5. javascript eval和JSON之间的联系

    eval函数的工作原理 eval函数会评估一个给定的含有JavaScript代码的字符串,并且试图去执行包含在字符串里的表达式或者一系列的合法的JavaScript语句.eval函数将把最后一个表达式 ...

  6. python中eval()函数的使用

    python中eval()函数的使用 python eval函数功能:将字符串str当成有效的表达式来求值并返回计算结果. 函数定义: eval(expression, globals=None, l ...

  7. python转换数据类型(int、float、str、eval、tuple、list、chr、ord、bin、oct、hex)

    1. 转换数据类型的函数 2. 转换数据类型的作⽤ 问:input()接收⽤户输⼊的数据都是字符串类型,如果⽤户输⼊1,想得到整型该如何操作? 答:转换数据类型即可,即将字符串类型转换成整型. 示例需 ...

  8. python中的EVAL函数的定义和用法!

    https://blog.csdn.net/weixin_42859280/article/details/84673079 Python 内置函数 Python 内置函数 描述: eval() 函数 ...

  9. eval语法报错 ie10_js eval 语法错误 急急急

    functionshowUserInfoList(responseText,statusText,xhr,form){varhtml='';varobj=eval("("+resp ...

  10. 简单介绍python的input,print,eval函数

    这篇文章主要为大家概述了python的input,print,eval函数,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助 input()函数 input()函数可以通过控制台 ...

最新文章

  1. FPGA中建立时间和保持时间不满足如何解决
  2. 在jQuery中删除事件处理程序的最佳方法?
  3. vue 数据(data)赋值问题
  4. 活动结束|金融圈第19期分享:数据系统如何防范金融非统性风险?
  5. 【TensorFlow】笔记1:入门笔记
  6. 也说说TIME_WAIT状态
  7. 分享我对领域驱动设计(DDD)的学习成果
  8. 基于visual Studio2013解决C语言竞赛题之0502最小数替换
  9. android java标准时间_java android中对list的时间进行排序
  10. centos65编译安装lamp和lnmp
  11. couchbase php,升级PHP7时couchbase扩展导入的bug
  12. Mysql中添加汉字乱码无法识别问题
  13. oracle 查看 统计更新时间,oracle查看和更新统计表的信息
  14. 文件上传的几个 - 示例
  15. 完整的网络安全解决方案
  16. uibot和按键精灵区别_uibot和按键精灵有什么区别?
  17. 质量保证QA与质量控制QC
  18. 2018-11-5-win10-uwp-异步转同步
  19. 视频编解码 — H264结构
  20. 97年的欧冠决赛 多特蒙德VS尤文 中里德尔的梦

热门文章

  1. java课程心得_Java课程的感想
  2. 2017年个人目标及计划
  3. 15/18位身份证号码验证的正则表达式总结
  4. Java游戏编程不完全详解-2
  5. VMware连接不上网络解决办法
  6. linux系统怎么打开菜单,Linux如何编辑开始菜单
  7. 【网络安全】实操XSS订单系统漏洞(利用盲打)
  8. 贝叶斯公式求解公园凉鞋问题
  9. 東京音頭 (东京音头) 歌词翻译
  10. 2015CGMC 参赛游戏名单