JavaScript中的eval()函数详解


Posted in Javascript onAugust 22, 2013

eval(“1+2”),-> 3

      动态判断源代码中的字符串是一种很强大的语言特性,几乎没有必要在实际中应用。如果你使用了eval(),你应当仔细考虑是否真的需要使用它。

一、eval()是一个函数还是一个运算符

eval()是一个函数,但由于它已经被当成运算符来对待了。。JavaScript语言的早期版本定义了eval函数,现代JavaScript解释器进行了大量的代码分析和优化。而eval的问题在于,用于动态执行的代码通常来讲不能分析,换句话说,如果一个函数调用了eval,那么解释器将无法对这个函数做进一步优化,而将eval定义为函数的另一个问题是,它可以被赋予其他的名字,var f=eval;那么解释器就无法放心的优化任何调用了f()的函数。而当eval是一个运算符的时候,就可以避免这些问题。

二、eval()

eval()只有一个参数。如果传入的参数不是字符串,它直接返回这个函数。如果参数是字符串,它会把字符串当成JavaScript代码进行编译,如果编译失败者抛出一个语法错误异常。如果编译成功,则开始执行这一段代码,并返回字符串中的最后一个表达式会或语句的值,如果最后一个表达式或语句没有值,则最终返回undefined。如果字符串抛出一个异常,这个异常将把该调用传递给eval()。

关于eval最重要的是,它使用了调用它的变量作用域环境。也就是说,它查找变量的值和定义新变量和函数的操作和局部作用域中的代码完全一样。如果一个函数定义了一个局部变量x,然后调用eval(“x”),它会返回局部变量的值。如果它调用eval(“x=1”),它会改变局部变量的值。如果函数调用了eval(“var y=2;”),它声明了一个新的局部变量y,同样地,一个函数可以通过如下代码声明一个局部变量:

eval(“function f(){return x+1;}”);

如果在最顶层的代码中调用eval,当然,它会作用于全局变量和全局函数。

需要注意的是,传递给eval的字符串必须在语法上将的通,不能通过eval往函数中任意粘贴代码片段,比如:eval(“return ;”)是没有意义的,因为return只有在函数中才起到作用,并且事实上,eval的字符串执行时的上下文环境和调用函数的上下文环境是一样的,这不能使其作为函数的一部分来运行。如果字符串作为一个单独的脚本是有语义的,那么将其传递给eval作参数是完全没有问题的,否则,eval会抛出语法错误异常。

三、全局eval()

eval()具有更改布局变量的能力,这对于JavaScript优化器来说是一个很大的问题。然而作为一种权宜之计,JavaScript解释器针对那些调用了eval的函数所做的优化并不多。但当脚本定义了eval的一个别名,且用另一个名称调用它,JavaScript解释器又会如何工作呢?为了让JavaScript解释器的实现更加简化,ECMAScript3标准规定了任何解释器都不允许对eval赋予别名。如果eval函数通过别名调用的话,则会抛出一个EavlError异常。

实际上,大多数的实现并不是这么做的。当通过别名调用时,eval会将其字符串当成顶层的全局代码来执行。执行的代码可能会定义新的全局变量和全局函数,或者给全局变量赋值,但却不能使用或者修改主调函数中的局部变量,因此,这不会影响到函数内的代码优化。

ECMAScript5是反对使用EavlError的,并且规范了eval的行为,“直接的eval”,当直接使用非限定的“eval”名称来调用eval()函数时,通常称为“直接eval”。直接调用eval()时,它总是在调用它的上下文作用域内执行。其他的间接调用则使用全局对象作为其上下文作用域,并且无法读、写、定义局部变量和函数。下面有一段示例代码:

var geval=eval;                //使用别名调用evla将是全局eval
var x="global",y="global";    //两个全局变量
function f(){                //函数内执行的是局部eval
    var x="local";            //定义局部变量
    eval("x += ' chenged';");//直接使用eval改变的局部变量的值
    return x;                //返回更改后的局部变量
}
Function g(){                //这个函数内执行了全局eval
    var y="local";
    geval("y += ' changed';"); //直接调用改变了全局变量的值
    return y;
}
console.log(f(),x);            //改变了布局变了,输出 “local changed global”
console.log(g(),y);            //改变了全局变量,输出    “local global changed”

全局的eval的这些行为不仅仅是处于代码优化其的需要而作出的一种折中方案,它实际上是一种非常有用的特性,它允许我们执行那些对上下文没有任何依赖的全局脚本代码段。真正需要eval来执行代码段的场景并不多见。但当你真的意识到它的必要性的时候,你更可能会使用全局eval而不是局部eval。

四、严格eval()

ECMAScript5严格模式对eval()函数的行为施加了更多的限制,甚至对标识符eval的使用也施加了限制。当在严格模式下调用eval时,或者eval执行的代码段以“Use strict” 指令开始,这里的eval是私有上下文环境中的局部eval。也就是说,在严格模式下,eval执行的代码段可以查询或更改局部变量,但不能在局部作用域中定义新的变量或函数。

此外,严格模式将“eval”列为保留字,这让eval()更像一个运算符。不能用一个别名覆盖eval()函数。并且变量名,函数名。函数参数或者异常捕获的参数都不能取名为eval。

宝剑锋从磨砺出,梅花香自苦寒来。

Javascript 相关文章推荐
HTML TO JavaScript 转换
Jun 26 Javascript
JavaScript mapreduce工作原理简析
Nov 25 Javascript
借助script进行Http跨域请求:JSONP实现原理及代码
Mar 19 Javascript
jQuery fadeTo方法调整图片的透明度使用介绍
May 06 Javascript
滚动条响应鼠标滑轮事件实现上下滚动的js代码
Jun 30 Javascript
jQuery层级选择器用法分析
Feb 10 Javascript
JavaScript 节流函数 Throttle 详解
Jul 04 Javascript
JS+Canvas绘制动态时钟效果
Nov 10 Javascript
JS实现简单tab选项卡切换
Oct 25 Javascript
vue中动态select的使用方法示例
Oct 28 Javascript
鸿蒙系统中的 JS 开发框架
Sep 18 Javascript
vue+iview实现分页及查询功能
Nov 17 Vue.js
from 表单提交返回值用post或者是get方法实现
Aug 21 #Javascript
jquery重新播放css动画所遇问题解决
Aug 21 #Javascript
JS性能优化笔记搜索整理
Aug 21 #Javascript
JS检测图片大小的实例
Aug 21 #Javascript
html5的自定义data-*属性和jquery的data()方法的使用示例
Aug 21 #Javascript
JavaScript 中的日期和时间及表示标准介绍
Aug 21 #Javascript
Ext JS 4实现带week(星期)的日期选择控件(实战二)
Aug 21 #Javascript
You might like
PHP操作xml代码
2010/06/17 PHP
PHP向浏览器输出内容的4个函数总结
2014/11/17 PHP
PHP基于MySQL数据库实现对象持久层的方法
2015/06/17 PHP
windows server 2008/2012安装php iis7 mysql环境搭建教程
2016/06/30 PHP
highchart数据源纵轴json内的值必须是int(详解)
2017/02/20 PHP
使用Firebug对js进行断点调试的图文方法
2011/04/02 Javascript
js判断滚动条是否已到页面最底部或顶部实例
2014/11/20 Javascript
bootstrap表单按回车会自动刷新页面的解决办法
2017/03/08 Javascript
jQuery表格(Table)基本操作实例分析
2017/03/10 Javascript
深入理解angular2启动项目步骤
2017/07/15 Javascript
js实现移动端轮播图效果
2020/12/09 Javascript
快速理解 JavaScript 中的 LHS 和 RHS 查询的用法
2017/08/24 Javascript
jQuery实现的简单无刷新评论功能示例
2017/11/08 jQuery
微信小程序之多列表的显示和隐藏功能【附源码】
2018/08/06 Javascript
vue2.x集成百度UEditor富文本编辑器的方法
2018/09/21 Javascript
vue 清空input标签 中file的值操作
2020/07/21 Javascript
[00:35]DOTA2上海特级锦标赛 EG战队宣传片
2016/03/04 DOTA
[15:07]lgd_OG_m2_BP
2019/09/10 DOTA
python 解析html之BeautifulSoup
2009/07/07 Python
初步解析Python中的yield函数的用法
2015/04/03 Python
python使用tkinter实现简单计算器
2018/01/30 Python
让你Python到很爽的加速递归函数的装饰器
2019/05/26 Python
一篇文章弄懂Python中的可迭代对象、迭代器和生成器
2019/08/12 Python
python实现飞机大战项目
2020/03/11 Python
scrapy爬虫:scrapy.FormRequest中formdata参数详解
2020/04/30 Python
聊聊python中的异常嵌套
2020/09/01 Python
python文件排序的方法总结
2020/09/13 Python
scrapy实践之翻页爬取的实现
2021/01/05 Python
利用HTML5中的Canvas绘制一张笑脸的教程
2015/05/07 HTML / CSS
Joe Fresh官网:加拿大时尚品牌和零售连锁店
2016/11/30 全球购物
GoDaddy英国:全球排名第一的域名注册商
2018/06/08 全球购物
审计主管岗位职责
2014/01/31 职场文书
物业保安员岗位职责
2014/03/14 职场文书
村党建工作汇报材料
2014/11/02 职场文书
北京天坛导游词
2015/02/12 职场文书
mysql性能优化以及配置连接参数设置
2022/05/06 MySQL