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 相关文章推荐
javascript跑马灯悬停放大效果实现代码
Dec 12 Javascript
2014 HTML5/CSS3热门动画特效TOP10
Dec 07 Javascript
在JavaScript中处理字符串之link()方法的使用
Jun 08 Javascript
使用 JavaScript 进行函数式编程 (一) 翻译
Oct 02 Javascript
AngularJS学习笔记(三)数据双向绑定的简单实例
Nov 08 Javascript
BootStrap3中模态对话框的使用
Jan 06 Javascript
Angular中$broadcast和$emit的使用方法详解
May 22 Javascript
微信小程序实现点击按钮移动view标签的位置功能示例【附demo源码下载】
Dec 06 Javascript
Vue-cli配置打包文件本地使用的教程图解
Aug 02 Javascript
使用vue-cli脚手架工具搭建vue-webpack项目
Jan 14 Javascript
Vue-router 报错NavigationDuplicated的解决方法
Mar 31 Javascript
Jquery ajax书写方法代码实例解析
Jun 12 jQuery
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
PHPEXCEL 使用小记
2013/01/06 PHP
PHP可变函数学习小结
2015/11/29 PHP
微信公众号判断用户是否已关注php代码解析
2016/06/24 PHP
详解php实现页面静态化原理
2017/06/21 PHP
laravel入门知识点整理
2020/09/15 PHP
linux mint下安装phpstorm2020包括JDK部分的教程详解
2020/09/17 PHP
JavaScript 基础知识 被自己遗忘的
2009/10/15 Javascript
基于jquery的跟随屏幕滚动代码
2012/07/24 Javascript
jquery插件开发之实现md5插件
2014/03/17 Javascript
jquery向上向下取整适合分页查询
2014/09/06 Javascript
js中日期的加减法
2015/05/06 Javascript
跟我学习javascript的作用域与作用域链
2015/11/19 Javascript
给angular加上动画效遇到的问题总结
2016/02/17 Javascript
js将字符串中的每一个单词的首字母变为大写其余均为小写
2017/01/05 Javascript
vue的无缝滚动组件vue-seamless-scroll实例
2017/12/18 Javascript
Angular5中调用第三方库及jQuery的添加的方法
2018/06/07 jQuery
vue组件之间的数据传递方法详解
2019/04/19 Javascript
vue3.0中的双向数据绑定方法及优缺点
2019/08/01 Javascript
JavaScript实现公告栏上下滚动效果
2020/03/13 Javascript
微信小程序12行js代码自己写个滑块功能(推荐)
2020/07/15 Javascript
[01:01:24]LGD vs Fnatic 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Python 数据结构之队列的实现
2017/01/22 Python
python使用tornado实现登录和登出
2018/07/28 Python
pygame游戏之旅 添加游戏界面按键图形
2018/11/20 Python
Django 中自定义 Admin 样式与功能的实现方法
2019/07/04 Python
Python datetime包函数简单介绍
2019/08/28 Python
解决django-xadmin列表页filter关联对象搜索问题
2019/11/15 Python
Python devel安装失败问题解决方案
2020/06/09 Python
工作违纪检讨书
2014/02/17 职场文书
高一军训决心书
2015/02/05 职场文书
2015新生加入学生会自荐书
2015/03/24 职场文书
实习感想范文
2015/08/10 职场文书
JavaScript+HTML实现学生信息管理系统
2021/04/20 Javascript
python缺失值的解决方法总结
2021/06/09 Python
Python中的 Set 与 dict
2022/03/13 Python
MySQL优化及索引解析
2022/03/17 MySQL