zoukankan      html  css  js  c++  java
  • 初涉JavaScript模式 (2) : 基本技巧

    尽量少用全局变量

    大量使用全局变量会导致的后果

    全局变量创建以后会在整个JavaScript应用和Web页面中共享。所有的全局变量都存在于一个全局命名空间内,很容易发生冲突

    不知不觉创建了全局变量

    其原因在于JavaScript的两个特性,第一个是JavaScript可直接使用变量而无需声明,第二个是JavaScript的暗示全局变量的概念,即任何变量如果未经声明,就为全局对象所有

    为了避免我们无意间创建了全局变量 我们可以使用var声明变量

    另一种创建暗示全局变量的反模式是带有var声明的链式赋值。

    产生上面结果的原因是 JavaScript的从右到左的操作符优先级 它的执行顺序是这样的

    ```javascript
       var a = (b = 0);
    
    ```
    

    解决方案也很简单 就是对链式赋值的所有变量都进行赋值,如下代码所示:

    ```javascript
    
      function demo(){
            var a,b;
            a = b = 0;
        }
    
    ```
    

    另一个避免全局变量大量使用的原因在于代码移植,你的代码在当前环境(主机)运行是没有问题的,但换个环境,全局变量可能会和存在于其他环境的变量发生冲突。

    全局变量的释放

    暗示全局变量和明确定义的全局变量有细微的不同,不同之处在于是否能用delete销毁,代码如下:

    以上代码说明暗示全局变量可以通过delete删除,而var定义则不能

    访问全局变量

    在浏览器下,可通过window属性在代码的任意位置访问到全局变量,但是也可能发生意外(声明了一个名为window的局部变量)。

    在其他环境下(如NodeJS),window就不叫window了,NodeJS下整个Runtime时期的全局变量是global,顾用window还不够严谨。

    解决方案代码如下:

    ```javascript
    
      var global = (function(){
        return this;
    }());
    
    ```
    

    按这种方式通常都能获取全局对象,因为this在函数内部作为一个函数调用(不是通过构造器创建也不是通过call,apply指定),往往指向全局对象

    但是如果你的代码运行在ES5的严格模式下,就不能这样用了,解决代码如下:

    变量及函数声明的提升

    JavaScript允许在函数的任意地方声明多个变量或函数,无论在哪里声明都等同于在函数顶部声明,这就是所谓的提升

    以上代码说明 var v1 被看做是局部变量的声明,所以打印出来的是undefined 这其实还涉及到一个变量对象(Variable Object)的问题,打印的时候他会先在Variable Object中找,如果找不到才会到window中去找,如果发现有了,则直接打印出来

    for循环的优化

    看到这里,你可能会觉得奇怪,for还有可以优化的地方吗?谈不上优化,就是一些注意点

    闲话不多说直接上代码:

    ```javascript
    //经典的for循环
    for(var i = 0; i < array.length; i++){
        //对array[i]进行操作
    }
    ```
    

    这种模式的问题在于每次循环都要访问数组的length,如果是数组还好,影响不是很大(速度变慢)。但是如果遍历的是DOM集合,我们知道在document下操作DOM是很耗性能的,而如果我们将length用变量保存起来,从而避免了每次循环对DOM的查询,在所有的浏览器中都会大大降低性能的损耗,其中在safari中速度会提高3倍,IE7中会提高170倍之多

    还有一个可以改进的是可以通过:

    ```javascript
    var array = [],len = array.length ;
    for(len,len--){
        //处理array[len]
    }
    ```
    

    这种模式 有2个好处,使用了最少的变量,逐步减至0,因为同0比较 比 同数组的长度比较速度更快

    还有一种while的模式,和这个类似,我就不贴代码了(嘿嘿)

    不要增加内置对象的原型

    以前喜欢写这种代码,被我英明的 “会哥” 提醒了一下,专门去看了下,反模式的典型啊。。。自我检讨下

    增加内置构造函数(Object,Array,Function)的原型是很爽的(埋下的坑迟早要填。。),但是这可能会严重影响可维护性,因为这将使你的代码变得更加不可预测,比如你重写了Array的slice方法,而别的工程师不知道,他得不到预期的结果(比全局对象污染更严重),如果一定要写也必须先准确的记录下来,并和团队交流清楚

    应该避免的一些小细节

    避免使用隐式类型转换

    JavaScript 在执行比较语句的时候会进行隐式类型转换,这也是为什么执行 false==0 或 "" == 0 这类比较语句会返回true的原因

    为了避免隐式转换造成的混淆不清,最好在使用比较语句的时候使用 === 和!===


    避免使用eval()

    eval 会将任意字符串当作JavaScript代码来执行(ES5 严格模式下使用eval会报错),eval会执行被修改过的代码(可能被客户端修改),会产生一些安全隐患

    eval的替代方案 使用浏览器自带的方法来解析JSON请求 JSON.parse() ,对于不支持parse的可以使用来自JSON.org的类库,还有就是通过setTimeout,setInterval,和function的构造函数来传递参数,在大部分情况下也会导致类似eval的隐患,如下代码所示:

    ```javascript
    //反模式
    setTimeout("func()" , 1000);
    setTimeout("func(1,2,3)" , 1000);
    //推荐的模式
    setTimeout(func , 1000);
    setTimeout(function(){
        func(1,2,3);
    } , 1000);
    如果传给setTimeout是字符串,JavaScript仍然会去以程序代码的方式去执行传递过来的字符串,如果一定要用eval,可以考虑用new Function()的方式来替代eval,代码如下:
    var code = "console.log(5)"
    new Function(code)(); //5
    ```
    

    使用parseInt的第二个参数

    通常第二个参数我们都是忽略,但是有时候会发生一些bug,比如如果我传的字符串是以0开头的就会出现错误,他会不确定是8进制还是10进制,所以最好还是加上进制。另外将一个字符串转换成数值有更快的方法,代码如下:

    ```javascript
    + “08” //8
    Number(“08”) //8
    ```
    

    这些方法比parseInt快很多,parseInt是解析而不是简单的转换,例如输入“08 soso” 除了parseInt 其他的都会返回NaN

    运行JSLint

    JSLint 可以检查你的代码,提前发现你的代码有哪些不足,写完代码后在JSLint上跑一遍,这是很好的编程模式(BUG伤不起啊)

    后记:

    第一次写这么长的博客,文中难免有错误之处,如果能指出感激不进

    这篇读书笔记,部分加入了自己工作中遇到的需求加以理解,如有不对之处,请联系我,共同进步

    作者:未然丶
  • 相关阅读:
    js中两个==和三个===的区别
    软件需求工程解析
    《我们应当怎样做需求分析》阅读笔记
    需求工程阅读笔记03
    个人小软件冲刺05
    个人小软件冲刺04
    需求工程阅读笔记02
    个人小软件冲刺03
    个人小软件冲刺02
    个人小软件冲刺01
  • 原文地址:https://www.cnblogs.com/ahjx777/p/3500333.html
Copyright © 2011-2022 走看看