eval使用总结:绑到不同的对象上
用JS做个小东西,需要动态执行脚本。于是尝试使用eval函数。
又因为届时会用到大量的函数和对象。所以不想通过命名来规避冲突。
但这样一来突然发现eval就无法满足我的需求了,因为它计算的出来的对象似乎全部绑上了全局的window。
var code = "var v=123;function test2(){return test() + 2} function test(){return v;}",
ns = {};
function testEval(){
eval(code)
alert("普通eval测试 " + (test?"污染":"没污染window"))
delete test;
eval.call(ns,code)
alert("eval 上下文测试 " + (ns.test?"加入命名空间":"没加入命名空间"))
alert("eval 上下文测试 " + (test?"污染window":"没污染"))
}
查看各类资料,无果。更有mozilla。他呀的eval函数的文档居然有2/3是劝你不要使用eval的。晕倒...
自己经过一番苦思,搞出一个变态的解决方案。大体的思路是:
1、制定一个规范,规定需要暴露的接口
2、外面手动的包一层函数,根据规范暴露接口
3、再计算这个对象。
Demo如下:
1 // code是动态的代码(实际的场景是读取目录下的js文件)
2 // 然后规定一个规范,在原先的代码上加上一个数组标记需要暴露的方法或对象
3 var code = "var EXPORT=[test,test2];\n var v=123;function test2(){return test() + 2} function test(){return v;}",
4 head = "new function(){",
5 end = "}",
6 ns = {},
7 magic;
8
9 ns.app = {}
10
11 // 测试函数
12 function nsmng(code){
13 var list = (code.slice(0,code.indexOf("\n"))||"").trim();//读取第一句
14 list = parseExportList(list); // 解析需要暴露的方法或者对象
15 magic=genMagicString(list); // 生成this.xxx=xxx;的代码
16 list = head + code +magic + end; // 拼接代码
17 ns.app= eval(list) // 然后一个匿名函数生成的对象到命名空间
18
19 alert(ns.app.test()) // 测试
20 alert(ns.app.test2())
21
22 // 异常
23 // alert(test)
24 // alert(test2)
25 // alert(v)
26 // alert(EXPORT)
27 }
28
29
30 function parseExportList(list){
31 if(/var\s*EXPORT\s*=\s*\[.*\]\s*\;*$/.test(list)){
32 return list.match(/\[.*\]/)[0].slice(1,-1)
33 }
34 throw "format error"
35 }
36
37 function genMagicString(list){
38 var data = list.split(',').map(function(obj){
39 return "this.%1=%1;".replace(/\%1/g,obj)
40 }).join("\n")
41 return (data)
42
43 }
44
45
46 nsmng(code);
这方面资料比较少,投递这篇,看看有没有人有更好的办法。