@@ -431,3 +431,85 @@ for-in 循环用于对非数组对象作遍历。通过for-in进行循环也被
431431
432432### 避免使用eval()
433433
434+ 当你想使用eval()的时候,不要忘了那句话“eval()是魔鬼”。这个函数的参数是一个字符串,它可以执行任意字符串。如果事先知道要执行的代码是有问题的(在运行之前),则没有理由使用eval()。如果需要在运行时动态生成执行代码,往往都会有更佳的方式达到同样的目的,而非一定要使用eval()。例如,访问动态属性时可以使用方括号:
435+
436+ // antipattern
437+ var property = "name";
438+ alert(eval("obj." + property));
439+ // preferred
440+ var property = "name";
441+ alert(obj[property]);
442+
443+ eval()同样有安全隐患,因为你需要运行一些容易被干扰的代码(比如运行一段来自于网络的代码)。在处理Ajax请求所返回的JSON数据时会常遇到这种情况,使用eval()是一种反模式。这种情况下最好使用浏览器的内置方法来解析JSON数据,以确保代码的安全性和数据的合法性。如果浏览器不支持JSON.parse(),你可以使用JSON.org所提供的库。
444+
445+ 记住,多数情况下,给setInterval()、setTimeout()和Function()构造函数传入字符串的情形和eval()类似,这种用法也是应当避免的,这一点非常重要,因为这些情形中JavaScript最终还是会执行传入的字符串参数:
446+
447+ // antipatterns
448+ setTimeout("myFunc()", 1000);
449+ setTimeout("myFunc(1, 2, 3)", 1000);
450+ // preferred
451+ setTimeout(myFunc, 1000);
452+ setTimeout(function () {
453+ myFunc(1, 2, 3);
454+ }, 1000);
455+
456+ new Function()的用法和eval()非常类似,应当特别注意。这种构造函数的方式很强大,但往往被误用。如果你不得不使用eval(),你可以尝试用new Function()来代替。这有一个潜在的好处,在new Function()中运行的代码会在一个局部函数作用域内执行,因此源码中所有用var定义的变量不会自动变成全局变量。还有一种方法可以避免eval()中定义的变量转换为全局变量,即是将eval()包装在一个立即执行的匿名函数内(详细内容请参照第四章)。
457+
458+ 看一下这个例子,这里只有un成为了全局变量,污染了全局命名空间:
459+
460+ console.log(typeof un);// "undefined"
461+ console.log(typeof deux); // "undefined"
462+ console.log(typeof trois); // "undefined"
463+
464+ var jsstring = "var un = 1; console.log(un);";
465+ eval(jsstring); // logs "1"
466+
467+ jsstring = "var deux = 2; console.log(deux);";
468+ new Function(jsstring)(); // logs "2"
469+
470+ jsstring = "var trois = 3; console.log(trois);";
471+ (function () {
472+ eval(jsstring);
473+ }()); // logs "3"
474+
475+ console.log(typeof un); // "number"
476+ console.log(typeof deux); // "undefined"
477+ console.log(typeof trois); // "undefined"
478+
479+ eval()和Function构造函数还有一个区别,就是eval()可以修改作用域链,而Function更像是一个沙箱。不管在什么地方执行Function,它只能看到全局作用域。因此它不会太严重的污染局部变量。在下面的示例代码中,eval()可以访问且修改其作用域之外的变量,而Function不能(注意,使用Function和new Function是完全一样的)。
480+
481+ (function () {
482+ var local = 1;
483+ eval("local = 3; console.log(local)"); // logs 3
484+ console.log(local); // logs 3
485+ }());
486+
487+ (function () {
488+ var local = 1;
489+ Function("console.log(typeof local);")(); // logs undefined
490+ }());
491+
492+ ## 使用parseInt()进行数字转换
493+
494+ 可以使用parseInt()将字符串转换为数字。函数的第二个参数是转换基数(译注:“基数”指的是数字进制的方式),这个参数通常被省略。但当字符串以0为前缀时转换就会出错,例如,在表单中输入日期的一个字段。ECMAScript3中以0为前缀的字符串会被当作八进制数处理(基数为8)。但在ES5中不是这样。为了避免转换类型不一致而导致的意外结果,应当总是指定第二个参数:
495+
496+ var month = "06",
497+ year = "09";
498+ month = parseInt(month, 10);
499+ year = parseInt(year, 10);
500+
501+ 在这个例子中,如果省略掉parseInt的第二个参数,比如parseInt(year),返回值是0,因为“09”被认为是八进制数(等价于parseInt(year,8)),而且09是非法的八进制数。
502+
503+ 字符串转换为数字还有两种方法:
504+
505+ +"08" // result is 8
506+ Number("08") // 8
507+
508+ 这两种方法要比parseInt()更快一些,因为顾名思义parseInt()是一种“解析”而不是简单的“转换”。但当你期望将“08 hello”这类字符串转换为数字,则必须使用parseInt(),其他方法都会返回NaN。
509+
510+ ## 编码风格
511+
512+ 确立并遵守编码规范非常重要,这会让你的代码风格一致、可预测、可读性更强。团队新成员通过学习编码规范可以很快进入开发状态、并写出团队其他成员易于理解的代码。
513+
514+ 在开源社区和邮件组中关于编码风格的争论一直不断(比如关于代码缩进,用tab还是空格?)。因此,如果你打算在团队内推行某种编码风格时,要做好应对各种反对意见的心理准备,而且要吸取各种意见,这对确立并一贯遵守某种编码风格是非常重要的,而不是更斤斤计较的纠结于编码风格的细节。
515+
0 commit comments