文档章节

怎样在不使用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
淮安
私信 提问
如何用javascript实现一个模板引擎

模板引擎简介 模板引擎是html渲染必不可少的工具,前端开发的同学经历了从最原始的字符串拼接、用数组push/join,发展到封装简单的string.format函数,再到功能更加强大的模板引擎,可以在模...

windyfancy
05/06
0
0
一次笔试引发的关于setTimeout的this的思考

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

JayJunG
2018/12/22
0
0
python核心编程--第十四章

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

fzyz_sb
2013/06/19
910
4
PHP将数组转为json出现的中文乱码的问题

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

Corwien
2016/01/26
575
7
我是如何让 Ruby 项目提升 10 倍速度的

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

limichange
2013/08/20
5.5K
17

没有更多内容

加载失败,请刷新页面

加载更多

Mybatis Plus性能分析

一、配置 /** * 性能分析 * @return */@Bean@Profile({"dev","test"})public PerformanceInterceptor performanceInterceptor (){ PerformanceInterceptor performanceInterceptor......

一个yuanbeth
16分钟前
4
0
一次写shell脚本的经历记录——特殊字符惹的祸

本文首发于微信公众号“我的小碗汤”,扫码文末二维码即可关注,欢迎一起交流! redis在容器化的过程中,涉及到纵向扩pod实例cpu、内存以及redis实例的maxmemory值,statefulset管理的pod需要...

码农实战
19分钟前
4
0
为什么阿里巴巴Java开发手册中不建议在循环体中使用+进行字符串拼接?

之前在阅读《阿里巴巴Java开发手册》时,发现有一条是关于循环体中字符串拼接的建议,具体内容如下: 那么我们首先来用例子来看看在循环体中用 + 或者用 StringBuilder 进行字符串拼接的效率...

武培轩
32分钟前
6
0
队列-链式(c/c++实现)

队列是在线性表功能稍作修改形成的,在生活中排队是不能插队的吧,先排队先得到对待,慢来得排在最后面,这样来就形成了”先进先出“的队列。作用就是通过伟大的程序员来实现算法解决现实生活...

白客C
40分钟前
32
0
聊聊nacos的notifyConfigInfo

序 本文主要研究一下nacos的notifyConfigInfo CommunicationController nacos-1.1.3/config/src/main/java/com/alibaba/nacos/config/server/controller/CommunicationController.java @Cont......

go4it
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部