文档章节

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

 如月王子
发布于 2016/06/12 19:58
字数 861
阅读 45
收藏 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
淮安
YUI Compressor 组件压缩 JavaScript 的一些原理

YUI Compressor 压缩 JavaScript 的内容包括: 移除注释 移除额外的空格 细微优化 标识符替换(Identifier Replacement) YUI Compressor 包括哪些细微优化呢? ,如果属性名是合法的 JavaSc...

晨曦之光
2012/03/09
0
0
JavaScript Gerden概述

1.对象 1.1 对象使用和属性 JavaScript中所有变量都是对象,除了null和undefined 1.2 对象作为数据类型 JavaScript对象可以作为哈希表使用,主要用来保存命名的键和值的对应关系 1.3 访问属性...

Seven_7
2014/07/29
0
0
python核心编程--第十四章

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

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

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

Corwien
2016/01/26
142
7
JavaScript之eval() 函数

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

Kxvz
2015/05/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

es6

在实际开发中,我们有时需要知道对象的所有属性,原生js给我们提供了一个很好的方法:Object.keys(),该方法返回一个数组 传入对象,返回属性名 var obj = {'a':'123','b':'345'};console.l...

不负好时光
7分钟前
0
0
叮!您收到一份超值Java基础入门资料!

摘要:Java语言有什么特点?如何最大效率的学习?深浅拷贝到底有何区别?阿里巴巴高级开发工程师为大家带来Java系统解读,带你掌握Java技术要领,突破重点难点,入门面向对象编程,以详细示例...

全部原谅
9分钟前
0
0
web.xml容器加载顺序

容器对于web.xml的加载过程是context-param >> listener >> fileter >> servlet

Aeroever
11分钟前
1
0
Docker容器日志查看与清理

1. 问题 docker容器日志导致主机磁盘空间满了。docker logs -f container_name噼里啪啦一大堆,很占用空间,不用的日志可以清理掉了。 2. 解决方法 2.1 找出Docker容器日志 在linux上,容器日...

muzi1994
12分钟前
0
0
J2Cache 和普通缓存框架有何不同,它解决了什么问题?

不少人看到 J2Cache 第一眼时,会认为这就是一个普普通通的缓存框架,和例如 Ehcache、Caffeine 、Spring Cache 之类的项目没什么区别,无非是造了一个新的轮子而已。事实上完全不是一回事!...

红薯
14分钟前
365
9

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部