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

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

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

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

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

eval会带来如下问题:安全

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

不幸的是,eval的功能很是强大,缺少经验的开发者常常过分使用这个命令。函数

尽管有警告,eval任然在浏览器内继续工做 - 即便是在严格模式下 -可是你一般能够避免使用它。过去它主要用来解析JSON字符串可是如今咱们有了更安全的JSON.parse方法。优化

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

// 咱们想要运行的函数
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/

相关文章
相关标签/搜索