文档章节

怎样在不使用eval的情况下从字符串中调用函数

 如月王子
发布于 2016/06/12 19:58
字数 861
阅读 51
收藏 3

在Javascript中eval是恶魔!MDN中关于eval的部分这样写道:

废除
该功能被废除。尽管现在浏览器依然支持此功能,在新的项目中并不鼓励这种用法。尽量避免使用它。

eval 会执行一段包含着代码的字符串,例如:

eval("var x = 'Hello from eval!';"); console.log(x);

eval会带来以下问题:

安全性:你的字符串能被第三方的Javascript库或者用户输入的内容注入。
调试:很难去调试错误 - 你将得不到发生错误的行数以及错误发生的点。
优化:Javascript解释器将不会预编译代码因为它随时可能改变。这样的做法通常比原生代码要运行的慢,即便是在解释器变得更有效率的前提下。

不幸的是,eval的功能非常强大,缺乏经验的开发者经常过度使用这个命令。

尽管有警告,eval任然在浏览器内继续工作 - 即使是在严格模式下 -但是你通常可以避免使用它。过去它主要用来解析JSON字符串但是现在我们有了更安全的JSON.parse方法。

然而,要是我们有一个包含函数名的字符串,比如说:

// 我们想要运行的函数
var fnstring = "runMe";

function runMe() {
    // do stuff
}

我们怎么样在不使用eval的前提下执行 runMe() 函数呢?我最近在使用HTML5 History API的时候就遇到了这个问题;pushState方法并不允许你将一个指向存储为一个函数以你你需要将它的名字定义为一个字符串。当你使用Web Workers和其他类似的序列化对象API是也会遇到相同的挑战。

最简单最安全的方法是编写列条件,例如:

// 我们想运行的函数
var fnstring = "runMe";

switch (fnstring) {
    case "functionX": functionX(); break;
    case "functionY": functionY(); break;
    case "functionZ": functionZ(); break;
    case "runMe": runMe(); break;
}

这种方式很安全,但是当你有一堆函数需要调用时非常低效而且痛苦。

一种更好的解决方法是使用window对象,它可以指向当前窗口以及其中所有的项目。我们可以来检查window中的fnstring是否是一个对象,如果它是一个函数那么就执行它。例如:

// 我们想要执行的函数
var fnstring = "runMe";

// 发现对象
var fn = window[fnstring];

// 对象是不是函数
if (typeof fn === "function") fn();

如果需要确保函数有一个预想的名字,你也可以进行其他检查。

要是我们想要调用的函数有参数怎么办 - 也许储存在一个数组里?没问题,我们只需要使用apply方法:

// 函数名和传递的参数

var fnstring = "runMe";
var fnparams = [1, 2, 3];

// 发现对象
var fn = window[fnstring];

// 对象是函数
if (typeof fn === "function") fn.apply(null, fnparams);

阻止我们使用eval的理由多种多样。比起eval来,上面的方法更加安全,更少发生错误,更易调试,并且通常能更快执行。我希望本文对你会有帮助。


在文章下面的评论中,有人提供了另一个方法

  setTimeout("runMe",0);

不过我记得setTimeout也调用了eval方法


本文译自博文How to Call a JavaScript Function From a String Without Using eval,原文地址:http://www.sitepoint.com/call-javascript-function-string-without-using-eval/

本文转载自:http://www.html-js.com/article/A-day-to-learn-how-JavaScript-without-using-the-eval-function-is-c...

共有 人打赏支持
粉丝 15
博文 177
码字总数 3194
作品 0
淮安
私信 提问
一次笔试引发的关于setTimeout的this的思考

之前对于setTimeout的this指向理解一直迷迷糊糊,在项目实践中也没有遇到相关问题,在面试时也没有被过关于这个问题,所以得过且过,直到最近的一次笔试碰到了令自己困惑的问题才去深入的了解...

JayJunG
2018/12/22
0
0
PHP将数组转为json出现的中文乱码的问题

将GBK编码的含有中文数组转为json格式,先将每个值进行urlencode,然后json_encode,最后urldecode即可。 2.将json转为数组 3.终极处理方法,对数组进行编码转换 用途:中文处理,在返回json时...

Corwien
2016/01/26
142
7
python核心编程--第十四章

14.1 可调用对象 许多的python对象都是我们所说的可调用的,即是任何能通过函数操作符“()”来调用的对象。要调用可调用对象,函数操作符得紧跟在可调用对象之后。python有4种可调用对象:...

fzyz_sb
2013/06/19
0
4
JavaScript之eval() 函数

定义和用法 eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。 语法 eval(string) 参数描述 string必需。要计算的字符串,其中含有要计算的 JavaScript 表达式或要执行的语句。...

Kxvz
2015/05/20
0
0
我是如何让 Ruby 项目提升 10 倍速度的

这篇文章是关于我怎样将我的ruby 珍宝contracts.ruby 提速10倍的。 contracts.ruby是我的一个项目,它用来为Ruby增加一些代码合约。它看起来像这样: 现在,只要add被调用,其参数与返回值都...

limichange
2013/08/20
5.4K
17

没有更多内容

加载失败,请刷新页面

加载更多

SpringCloud 与 SpringBoot 的版本兼容

Spring Cloud Finchley 构建并使用 Spring Boot 2.0.x,预计不会与Spring Boot 1.5.x一起使用Spring Cloud Edgware Spring Boot 1.5.xDalston 和 Edgware 发布版基于Spring Boot 1......

晨猫
12分钟前
1
0
microtime 记录的时间点,以毫秒来显示,并显示每一阶段占用百分比。统计代码执行时间。

function mini_bench_to($arg_t, $arg_ra=false){ $tttime=round((end($arg_t)-$arg_t['start'])*1000,4); if ($arg_ra) $ar_aff['total_time']=$tttime; else $aff="total......

lwkai
13分钟前
2
0
Docker 解决容器时间与主机时间不一致的问题三种解决方案

这篇文章主要介绍了Docker 解决容器时间与主机时间不一致的问题的相关资料,这里提供了三种方法,供大家参考,需要的朋友可以参考下 Docker容器时间与主机时间不一致 通过date命令查看时间 查...

Jack088
15分钟前
2
0
neo4j 开启远程web访问7474端口 以 用浏览器打开远程neo4j的web控制台界面

一、对于3.0以前的版本 在安装目录的 $NEO4J_HOME/conf/neo4j.conf 文件内,找到下面一行,将注释#号去掉就可以了 #dbms.connector.https.address=localhost:7474 改为 dbms.connector.https...

Airship
15分钟前
2
0
集合排序

根据指定规则,对集合元素进行自定义排序 List<Map<String, Object>> list= data.stream().sorted(new Comparator<Map>() { @Override public int compare(Map o1, Map o2) { Comparator c =......

zhaochaochao
17分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部