如何在这种情况下避免使用eval()?

时间:2014-02-20 02:59:34

标签: javascript json eval

我是否应该使用eval()开始一场战争,我试图就如何在以下情况中避免(如果可能)使用eval()进行建设性讨论?

我正在将远程html模板加载到SPA中,以保存我正在加载json的调用,如下所示:

{
  "template":"",
  "contentScript":"",
  "viewModel":""
}

如果模板是html,则contentScript是组合脚本文件,viewModel是单个脚本文件。

ContentScript

当收到json请求时(来自server或localdb)我创建了一个匿名函数(所以所有变量都本地作用于此模板脚本),用于看起来像这样的内容:

(function(event, view) 
 {
   // js content here
 });

其中事件对象是contentScript和viewmodel使用pub / sub模式进行通信的共享对象,而view对象是作为模板的DOM元素。

我能看到让这种模式运作的唯一方法是使用以下代码:

var script = 'function(event, view) {' + json.contentScript + '});';
views[name].script = eval(script);

其中views [name]是SPA中所有模板的集合,因此我可以获取它们并使用名称轻松重新绑定它们。

每次渲染视图时我都可以简单地调用(执行脚本):

views[name].script.apply(window, [ views[name].eventObj, views[name].view ]);

视图模型

视图模型略有不同,因为我需要该对象的属性才能显示绑定,因此它不能是匿名函数。为了实现所需的结果,我将viewModel对象创建为对象文字,如:

var viewmodel = 
{
   init: function(event, view)
   {
      this.event = event;
      this.view = view;
   },

   ... other stuff
}

当收到viewModel json时,我在它上面运行一个正则表达式,以确保init签名符合预期,然后eval()就像:

eval(json.viewModel);
views[name].model = observable(viewmodel); // viewmodel var is available from eval'ing the contentScript

views[name].model.init(views[name].eventObj, views[name].view);

新功能

我也尝试使用Function('script as string'),这也是不赞成的。但是这并不支持这两种情况,因为它在我的匿名函数周围创建了一个匿名函数,需要额外的一步来检查参数以将变量传递给我的匿名函数。更重要的是,它还隐藏了对象文字的属性,防止数据绑定工作。

结论

我看不出我在这里做的任何问题,但我很好奇如何使用其他方法实现这一点。我花了很多时间尝试不同的想法,没有一个允许两个场景有效地工作。

1 个答案:

答案 0 :(得分:1)

  

如何在这种情况下避免使用eval()?

     

我看不出我在这里做的任何问题,但我很好奇如何使用其他方法实现这一点。我花了很多时间尝试不同的想法,没有一个允许两个场景有效地工作。

我相信这个问题值得回答。

由于您想在本地范围内评估您的Javascript代码字符串,因此我不相信在您的情况下可以避免使用eval。一句警告。

  

eval()是一个危险的函数,它使用调用者的特权执行它传递的代码。如果您使用可能受恶意方影响的字符串运行eval(),您最终可能会使用您的网页/扩展程序的权限在用户的计算机上运行恶意代码。更重要的是,第三方代码可以看到调用eval()的范围,这可能导致类似函数不受影响的可能攻击。

可以在Perfection Kills by kangax

找到一些有趣的阅读材料