作者:gcbeen

日期:2013年09月21日

一、全局变量的问题

全局变量对于任何代码块,都是可读可写,这是javascript最大的语法缺点,对代码的模块化和重复使用非常不利。例如:两个不同的部分定义同名但不同作用的全局变量的时候,命名冲突在所难免。

web页面包含不是该页面开发这所写的代码也是非常常见的,例如:

  • 第三方的javascript库
  • 广告方的脚本代码
  • 第三方用户跟踪和分析脚本代码
  • 不同类型的小组件,标志和按钮 比方说,第三方脚本定义了一个全局变量(result),接着,在你的函数中也定义了一个全局变量(result)。其结果就是后面的变量覆盖前面的,第三方的变量(result)就没作用了。

因此,要想和其他脚本成为好邻居,应尽可能减少使用全局变量。

由于Javascript的两个特征,不自觉地创建出全局变量出乎意料的容易。首先,你可以甚至不需要声明就可以使用变量;第二,Javascript有隐含的全局概念,意味着你不声明的任何变量都会成为一个全局对象属性。

    function sum(x, y) {
      result = x + y; // result 为全局变量
      return result;
    }

应改为:

    function sum(x, y) {
        var result = x + y;
        return result;
    }

语句的合并

    var a = b = 0;

实际是:

    b = 0;
    var a = b;

二、所有的变量都声明在函数头部

这样做的好处:

  • 提供一个单一的地方寻找功能所需的所有局部变量
  • 防止变量在定义之前使用的逻辑错误
    function func() {
      var a = 1,
          b = 2,
          sum = a + b,
          myobject = {},
          i,
          j;
      // function body
    }

你也可以在声明的时候做一些实际的工作

    function updateElement() {
      var el = document.getElementById("result"),
          style = el.style;
      //function body
    }

Javascript中,你可以在函数的任何位置声明多个var语句,并且他们就好象是在函数顶部声明一样发挥作用,这种行为称为hoisting(悬置/置顶解析/预解析)。

当你使用了一个变量,然后不久在函数中又声明的话,就可能产生逻辑错误。

对于Javascript,只要你的变量是在同一作用域中(同一函数),他都被当作声明了的,即使是它在var声明前使用的时候。

    myname = "global";
    function func() {
      alert(myname);        // "undefined"
      var myname = "local";
      alert(myname);        // "local"
    }

上面代码等同于:

    myname = "global";
    function func() {
      var myname;
      alert(myname);
      myname = "local";
      alert(myname);
    }

for循环

function looper() { var i = 0, max, myarray = []; for (max = myarray.length; i < max; i += 1) { ... } } while循环

    function looper() {
      var myarray = [],
          i = myarray.length;
      while (i) {
        i -= 1;
        // body
      }
    }

for-in循环

    var man = {
       hands: 2,
       legs: 2,
       heads: 1
    };
    var i;
    for ( i in man) {
      if (Object.prototype.hasOwnProperty.call(man, i) {
        console.log(i, ":", man[i]);
      }
    }

避免隐式类型转换

    var zero = 0;
    if (zero === false) {
      //不执行
    }

    if (zero == false) {
      //执行
    }

避免使用eval()

使用eval()带来安全隐患,被执行的代码(例如从网络来)可能被篡改。

例如:当处理Ajax请求得到的JSON的时候,最好使用Javascript内置方法(JSON.parse())来解析JSON,以确保有效。或来自于JSON.org的库。

给setInterval(), setTimeout()和Function()构造函数传递字符串,大部分与使用eval类似。因此避免给他们传递字符串

    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()。

    var jsstring = "var un = 1; console.log(un);";
    eval(jsstring);

    jsstring = "var deux = 2; console.log(deux);";
    new Function(jsstring)();

    jsstring = "var trois = 3; console.log(trois);";
    (function () {
       eval(jsstring);
    }());
    
    console.log(typeof un);      // number
    console.log(typeof deux);    // "undefined"
    console.log(typeof trois);   // "undefined"

另外eval会干扰作用域链,污染本地变量。

    (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);")(); // log undefined
     }());

命名函数表达式

函数声明: function 函数名称(参数:可选) { 函数体 } 函数表达式: function 函数名称(可选)(参数:可选){ 函数体 };

  var func = function () {};

Javascript Module模式

基本用法:

    var Calculator = function (eq) {
      var eqCt1 = document.getElementById(eq);

      return {
        add: function (x, y) {
          var val = x + y;
          eqCt1.innerHTML = val;
        }
      }
    };
    var calculator = new Calculator('eq');
    calculator.add(2, 2);

匿名闭包

    (function () {
       //....所有的变量和function都在这里声明,并且作用域也只能在这个匿名闭包里
     }());

引入全局变量

    (function ($, YAHOO) {
       // coding
     }(jQuery, YAHOO));

返回全局变量

    var blogModule = (function () {
      var my = {},
          privateName = '博客苑';
      
      function privateAddTopic(data) {
        // coding
      }

      my.Name = privateName;
      my.AddTopic = function (data) {
        privateAddTopic(data);
      };

      return my;
    } ());


blog comments powered by Disqus