zoukankan      html  css  js  c++  java
  • 高质量JavaScript代码书写基本要点学习

    高质量JavaScript代码书写基本要点学习
    可维护的代码意味着:
    •可读的
    •一致的
    •可预测的
    •看上去就像是同一个人写的
    •已记录
     
    最小全局变量(Minimizing Globals)
     
    JavaScript通过函数管理作用域。在函数内部声明的变量只在这个函数内部,函数外面不可用。另一方面,全局变量就是在任何函数外面声明的或是未声明直接简单使用的。
     
    每个JavaScript环境有一个全局对象,当你在任意的函数外面使用this的时候可以访问到。你创建的每一个全部变量都成了这个全局对象的属性。在浏览器中,方便起见,该全局对象有个附加属性叫做window,此window(通常)指向该全局对象本身。
     
    隐式全局变量和明确定义的全局变量间有些小的差异,就是通过delete操作符让变量未定义的能力。
    •通过var创建的全局变量(任何函数之外的程序中创建)是不能被删除的。
    •无var创建的隐式全局变量(无视是否在函数中创建)是能被删除的。
     
    这表明,在技术上,隐式全局变量并不是真正的全局变量,但它们是全局对象的属性。属性是可以通过delete操作符删除的,而变量是不能的:
     
    // 定义三个全局变量
    var global_var = 1;
    global_novar = 2; // 反面教材
    (function () {
       global_fromfunc = 3; // 反面教材
    }());
     
    // 试图删除
    delete global_var; // false
    delete global_novar; // true
    delete global_fromfunc; // true
     
    // 测试该删除
    typeof global_var; // "number"
    typeof global_novar; // "undefined"
    typeof global_fromfunc; // "undefined"
     
    在ES5严格模式下,未声明的变量(如在前面的代码片段中的两个反面教材)工作时会抛出一个错误。
     
    function func() {
       var a = 1,
           b = 2,
           sum = a + b,
           myobject = {},
           i,
           j;
       // function body...
    }
     
    您可以使用一个var语句声明多个变量,并以逗号分隔。像这种初始化变量同时初始化值的做法是很好的。这样子可以防止逻辑错误(所有未初始化但声明的变量的初始值是undefined)和增加代码的可读性。在你看到代码后,你可以根据初始化的值知道这些变量大致的用途,例如是要当作对象呢还是当作整数来使。
     
    这就是为什么当你循环获取值时,缓存数组(或集合)的长度是比较好的形式,正如下面代码显示的:
     
    for (var i = 0, max = myarray.length; i < max; i++) {
       // 使用myarray[i]做点什么
    }
     
    这样,在这个循环过程中,你只检索了一次长度值。
     
    还有两种变化的形式,其又有了些微改进,因为:
    •少了一个变量(无max)
    •向下数到0,通常更快,因为和0做比较要比和数组长度或是其他不是0的东西作比较更有效率
     
    第一种变化的形式:
     
    var i, myarray = [];
    for (i = myarray.length; i–-;) {
       // 使用myarray[i]做点什么
    }
     
    第二种使用while循环:
     
    var myarray = [],
        i = myarray.length;
    while (i–-) {
       // 使用myarray[i]做点什么
    }
     
    这些小的改进只体现在性能上,此外JSLint会对使用i–-加以抱怨。
     
    (不)扩展内置原型((Not) Augmenting Built-in Prototypes)
     
    扩增构造函数的prototype属性是个很强大的增加功能的方法,但有时候它太强大了。
     
    增加内置的构造函数原型(如Object(), Array(), 或Function())挺诱人的,但是这严重降低了可维护性,因为它让你的代码变得难以预测。使用你代码的其他开发人员很可能更期望使用内置的JavaScript方法来持续不断地工作,而不是你另加的方法。
     
    另外,属性添加到原型中,可能会导致不使用hasOwnProperty属性时在循环中显示出来,这会造成混乱。
     
    因此,不增加内置原型是最好的。你可以指定一个规则,仅当下面的条件均满足时例外:
    •可以预期将来的ECMAScript版本或是JavaScript实现将一直将此功能当作内置方法来实现。例如,你可以添加ECMAScript 5中描述的方法,一直到各个浏览器都迎头赶上。这种情况下,你只是提前定义了有用的方法。
    •如果您检查您的自定义属性或方法已不存在——也许已经在代码的其他地方实现或已经是你支持的浏览器JavaScript引擎部分。
    •你清楚地文档记录并和团队交流了变化。
     
    避免隐式类型转换(Avoiding Implied Typecasting )
     
    JavaScript的变量在比较的时候会隐式类型转换。这就是为什么一些诸如:false == 0 或 “” == 0 返回的结果是true。为避免引起混乱的隐含类型转换,在你比较值和表达式类型的时候始终使用===和!==操作符。
     
    避免(Avoiding) eval()
     
    如果你现在的代码中使用了eval(),记住该咒语“eval()是魔鬼”。此方法接受任意的字符串,并当作JavaScript代码来处理。当有问题的代码是事先知道的(不是运行时确定的),没有理由使用eval()。如果代码是在运行时动态生成,有一个更好的方式不使用eval而达到同样的目标。例如,用方括号表示法来访问动态属性会更好更简单:
     
    // 反面示例
    var property = "name";
    alert(eval("obj." + property));
     
    // 更好的
    var property = "name";
    alert(obj[property]);
     
    使用eval()也带来了安全隐患,因为被执行的代码(例如从网络来)可能已被篡改。这是个很常见的反面教材,当处理Ajax请求得到的JSON 相应的时候。在这些情况下,最好使用JavaScript内置方法来解析JSON相应,以确保安全和有效。若浏览器不支持JSON.parse(),你可以使用来自JSON.org的库。
     
    同样重要的是要记住,给setInterval(), setTimeout()和Function()构造函数传递字符串,大部分情况下,与使用eval()是类似的,因此要避免。在幕后,JavaScript仍需要评估和执行你给程序传递的字符串:
     
    // 反面示例
    setTimeout("myFunc()", 1000);
    setTimeout("myFunc(1, 2, 3)", 1000);
     
    // 更好的
    setTimeout(myFunc, 1000);
    setTimeout(function () {
       myFunc(1, 2, 3);
    }, 1000);
     
    如果你绝对必须使用eval(),你可以考虑使用new Function()代替。有一个小的潜在好处,因为在新Function()中作代码评估是在局部函数作用域中运行,所以代码中任何被评估的通过var定义的变量都不会自动变成全局变量。另一种方法来阻止自动全局变量是封装eval()调用到一个即时函数中。
     
    考虑下面这个例子,这里仅un作为全局变量污染了命名空间。
     
    console.log(typeof un);    // "undefined"
    console.log(typeof deux); // "undefined"
    console.log(typeof trois); // "undefined"
     
    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"
     
    console.log(typeof un); // number
    console.log(typeof deux); // "undefined"
    console.log(typeof trois); // "undefined"
     
    另一间eval()和Function构造不同的是eval()可以干扰作用域链,而Function()更安分守己些。不管你在哪里执行Function(),它只看到全局作用域。所以其能很好的避免本地变量污染。在下面这个例子中,eval()可以访问和修改它外部作用域中的变量,这是Function做不来的(注意到使用Function和new Function是相同的)。
     
    (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
    }());
     
    使用parseInt()你可以从字符串中获取数值,该方法接受另一个基数参数,这经常省略,但不应该。当字符串以”0″开头的时候就有可能会出问题,例如,部分时间进入表单域,在ECMAScript 3中,开头为”0″的字符串被当做8进制处理了,但这已在ECMAScript 5中改变了。为了避免矛盾和意外的结果,总是指定基数参数。
     
    var month = "06",
        year = "09";
    month = parseInt(month, 10);
    year = parseInt(year, 10);
    此例中,如果你忽略了基数参数,如parseInt(year),返回的值将是0,因为“09”被当做8进制(好比执行 parseInt( year, 8 )),而09在8进制中不是个有效数字。
     
    替换方法是将字符串转换成数字,包括:
     
    +"08" // 结果是 8
    Number("08") // 8
     
    这些通常快于parseInt(),因为parseInt()方法,顾名思意,不是简单地解析与转换。但是,如果你想输入例如“08 hello”,parseInt()将返回数字,而其它以NaN告终。
     
    要记住,建立和坚定不移地遵循规范要比纠结于规范的细节重要的多。
    总之,总是使用花括号,并始终把在与之前的语句放在同一行:
     
    function func() {
       return {
          name : "Batman"
       };
    }
    关于分号注:就像使用花括号,你应该总是使用分号,即使他们可由JavaScript解析器隐式创建。这不仅促进更科学和更严格的代码,而且有助于解决存有疑惑的地方,就如前面的例子显示。
    空格的使用同样有助于改善代码的可读性和一致性。在写英文句子的时候,在逗号和句号后面会使用间隔。在JavaScript中,你可以按照同样的逻辑在列表模样表达式(相当于逗号)和结束语句(相对于完成了“想法”)后面添加间隔。
    适合使用空格的地方包括:
    •for循环分号分开后的的部分:如for (var i = 0; i < 10; i += 1) {...}
    •for循环中初始化的多变量(i和max):for (var i = 0, max = 10; i < max; i += 1) {...}
    •分隔数组项的逗号的后面:var a = [1, 2, 3];
    •对象属性逗号的后面以及分隔属性名和属性值的冒号的后面:var o = {a: 1, b: 2};
    •限定函数参数:myFunc(a, b, c)
    •函数声明的花括号的前面:function myFunc() {}
    •匿名函数表达式function的后面:var myFunc = function () {};
     
    使用空格分开所有的操作符和操作对象是另一个不错的使用,这意味着在+, -, *, =, <, >, <=, >=, ===, !==, &&, ||, +=等前后都需要空格。
    最后需要注意的一个空格——花括号间距。最好使用空格:
    •函数、if-else语句、循环、对象字面量的左花括号的前面({)
    •else或while之间的右花括号(})
    最重要的习惯,然而也是最难遵守的,就是保持注释的及时更新,因为过时的注释比没有注释更加的误导人。
  • 相关阅读:
    Spring 框架Bean的初始化和销毁---方式:BeanPostProcessor后置处理器
    Spring 框架Bean的初始化和销毁 -- 方式:@PostConstruct注解和@PreDestroy注解
    Spring 框架Bean的初始化和销毁---方式:InitializingBean接口,DisposableBean接口
    Spring 框架Bean的初始化和销毁 ---方式: @Bean(initMethod = "init",destroyMethod = "destroy")
    消息队列入门理解
    springboot的定时任务使用(动态cron,缓存提速)
    【SpringBoot WEB 系列】RestTemplate 之自定义请求头
    【SpringBoot WEB系列】WebFlux静态资源配置与访问
    【SpringBoot WEB系列】静态资源配置与读取
    【SpringCloud 系列】Eureka 注册中心初体验
  • 原文地址:https://www.cnblogs.com/doit8791/p/3209497.html
Copyright © 2011-2022 走看看