作者senser (彷佛曾经一起死过)
看板Ajax
标题Re: [问题] 关於变数名称的命名问题
时间Sat Aug 27 17:42:51 2011
eval()可以把一段字串当成arbitrary js在runtime compile并执行
您要的结果 可以用eval简单达成
事实上eval可能也是为了类似您这类的需求设计的(这我就不确定瞜)
我们总是被告知"eval is evil"
这是为什麽呢?
1.首先是performace
在你在开启一个页面时 你的js会被compiled
呼叫compiler会耗掉资源和时间
而我们目前的browser可以在非常短的时间内compile成千上万行js
为了几行东西在compile一次很不符合成本效益
2.第二点是安全性
Douglas Crockford在Good Part里说
The eval function also compromises the security of your application because
it grants too much authority to
the eval'd text.
以client-side来说 用eval会把许多错误隐藏起来而难以debug
举例来说 把不合法的JSON包在eval中 就可以躲过 JsLint的侦测(难怪他会不爽)
而里面的错误也不会被debugger理解 只是知道里面有东西出错了
然而实际上 真的以安全性的角度来说 client-side顶多就break页面 倒是还好
真的和安全性有关的 是server-side的eval
很多script如php都有eval类似的function 这时候就要非常小心 (虽然超出js范畴)
尤其是user-supplied data from client-side
试想如果你 eval($_POST['username'])
马上就有严重的injection漏洞
3.还有一个问题就是难读与难以maintain
这应该非常明显
4.另外有一个问题较少被提到 就是context的问题
eval会继承caller的context而遭到local variable的污染
有些人不认为这是个问题 但我想如果你想要执行一段arbitrary js
你可能会想要乾净点的context
回到我们的问题
eval()的alternatives很多
Stoyan Stefanov 的javascript design patterns中介绍了几种方法
1.如果是想达成像blockname1 blockname2这种实做 可以考虑采用array
如书中例子
// antipattern
var property = "name";
alert(eval("obj." + property));
// preferred
var property = "name";
alert(obj[property]);
2.在Function的constructor 或是setTimeout的函数中 传一个string的效果和eval其实是类似
所以也要尽量避免 (事件的inline binding也是)
// antipatterns
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);
// preferred
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);
3.
eval里的var宣告会污染caller context (如果这不是你的本意的话)
这种时候可以用new Function或是function closure隔绝起来
var jsstring = "var un = 1; console.log(un);";
eval(jsstring); // logs "1"
jsstring = "var deux = 2; console.log(deux);";
new Function(jsstring)(); // logs "2"
jsstring = "var trois = 3; console.log(trois);";
(function () {
eval(jsstring);
}()); // logs "3"
以上un会污染caller scope而deux和trois不会(也就是说 外面读不到这两个变数)
4.最後一点是第3点的反向思考
eval不仅会污染caller scope 也会被外面影响 (因为共享一个scope)
这时候Function constructor可以解决这问题
比较以下:
(function () {
var local = 1;
eval("local = 3; console.log(local)"); // logs 3
console.log(local); // logs 3
}());
(function () {
var local = 1;
Function("console.log(typeof local);")(); // logs undefined
}());
(这解决了eval的context问题 然而 Douglas Crockford并不推这种方法
因为Function constructor其实就是一种eval 只是对scoping有不同的处理)
以上的想法和例子大部分都出自於Good Part和Javascript Design Patterns
如果各位没有书的话 可以参考以下网路文章
http://javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval/
http://devlicio.us/blogs/sergio_pereira/archive/2009/03/31/javascript-avoid-the-evil-eval.aspx
希望对您有帮助~
※ 引述《tas72732002 (葱头)》之铭言:
: 想请问一下 可否用回圈产生不同的变数名称 例如:
: for(var i=0;i<=10;i++){
: var blockname + i = i ;
: }
: 希望最後的结果是
: blockname1 = 1;
: blockname2 = 2;
: blockname3 = 3;
: 可以这样命名吗??
※ 引述《tas72732002 (葱头)》之铭言:
: 想请问一下 可否用回圈产生不同的变数名称 例如:
: for(var i=0;i<=10;i++){
: var blockname + i = i ;
: }
: 希望最後的结果是
: blockname1 = 1;
: blockname2 = 2;
: blockname3 = 3;
: 可以这样命名吗??
※ 引述《tas72732002 (葱头)》之铭言:
: 想请问一下 可否用回圈产生不同的变数名称 例如:
: for(var i=0;i<=10;i++){
: var blockname + i = i ;
: }
: 希望最後的结果是
: blockname1 = 1;
: blockname2 = 2;
: blockname3 = 3;
: 可以这样命名吗??
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 71.104.223.87
※ 编辑: senser 来自: 71.104.223.87 (08/27 17:43)
※ 编辑: senser 来自: 71.104.223.87 (08/27 17:51)
1F:推 s25g5d4:eval容易被XSS吧.. 08/27 18:43
2F:→ senser:对 eval 千万不要塞可以被使用者窜改的参数 如果他只eval 08/28 02:13
3F:→ senser:你的站或软体提供的值 就较无此方面的问题 08/28 02:14