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之间的右花括号(})
    最重要的习惯,然而也是最难遵守的,就是保持注释的及时更新,因为过时的注释比没有注释更加的误导人。
  • 相关阅读:
    21.Merge Two Sorted Lists 、23. Merge k Sorted Lists
    34. Find First and Last Position of Element in Sorted Array
    leetcode 20. Valid Parentheses 、32. Longest Valid Parentheses 、301. Remove Invalid Parentheses
    31. Next Permutation
    17. Letter Combinations of a Phone Number
    android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事项
    oc 异常处理
    oc 类型判断
    oc Delegate
    oc 协议
  • 原文地址:https://www.cnblogs.com/doit8791/p/3209497.html
Copyright © 2011-2022 走看看