文档章节

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

 如月王子
发布于 2016/06/12 19:58
字数 861
阅读 48
收藏 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
python核心编程--第十四章

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

fzyz_sb
2013/06/19
0
4
JavaScript Gerden概述

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

Seven_7
2014/07/29
0
0
PHP将数组转为json出现的中文乱码的问题

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

Corwien
2016/01/26
142
7
JavaScript学习笔记——eval函数

eval()只有一个参数: 参数不是字符串,直接返回这个参数 - 是字符串,会被当成JavaScript代码进行编译 1)编译失败抛出一个语法错误 2)编译成功,则执行这段代码 2. eval()使用了调用它的变...

Acejerry
2016/01/19
47
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周日乱弹 —— 小心着凉 @红薯

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @莱布妮子:5.33起,其声呜呜然,如怨如慕,如泣如诉。余音袅袅,不绝如缕。分享Arch Enemy的单曲《Bridge Of Destiny (2009)》 《Bridge Of...

小小编辑
24分钟前
19
0
what f,,

anlve
今天
2
0
初级开发-编程题

` public static void main(String[] args) { System.out.println(changeStrToUpperCase("user_name_abc")); System.out.println(changeStrToLowerCase(changeStrToUpperCase("user_name_abc......

小池仔
今天
10
0
现场看路演了!

HiBlock
昨天
20
0
Rabbit MQ基本概念介绍

RabbitMQ介绍 • RabbitMQ是一个消息中间件,是一个很好用的消息队列框架。 • ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。Connection是RabbitMQ的s...

寰宇01
昨天
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部