• JavaScript 的变量作用域及闭包


    作用域

    JavaScript 的变量作用域是按照函数划分的,为了快速的了解它的特性,我们通过实例来进行演示。

    实例一:

    <script type="text/javascript">

    var i = 1;

    //  弹出内容为 1 true 的提示框

           alert(window.i + ' ' + (window.i == i));

    </script>

    分析:

    在全局定义的变量其实就是 window 对象的属性。

    上面的例子可以看到,我们定义全局变量的同时,window 对象会产生一个相应的属性,如何让我们的代码避免产生这个属性呢,看下面的例子。

    实例二:

    <script type="text/javascript">

           var document = 1;

           window.onload = function(){

                  alert(document);

           }

           // 弹出内容为 1 的提示框

           alert(window.document);

    </script>

    这种情况是我们不想看到的,我们可以这么做:

    <script type="text/javascript">

           function test(){

                  var document = 1;

                  window.onload = function(){

                         alert(document);

                  }

           }

           test();

           // 弹出内容为 [object] 的提示框

           alert(window.document);

    </script>

    为了使代码更加简洁,我们可以这样:

    <script type="text/javascript">

           (function(){

                  var document = 1;

                  window.onload = function(){

                         alert(document);

                  }

           })();

           // 弹出内容为 [object] 的提示框

           alert(window.document);

    </script>

    分析:

    这种运行匿名方法的形式,在 JavaScript 的主流框架中经常见到,这样做可以避免产生不必要的 window 对象的属性,减少冲突的可能。

    实例三:
    <script type="text/javascript">
     (function(){
      if('1' == '1'){
       var i = 1;
      }
      // 弹出内容为 1 的提示框
      alert(i);
     })();
    </script>
    分析:
    变量的作用域是整个函数,不是{}块。

    实例四:

    <script type="text/javascript">

           var i = 1;

           // 弹出内容为 1 的提示框

           alert(i);

           var i = 2;

           // 弹出内容为 2 的提示框

           alert(i);

    </script>

    分析:

    一个变量可以被重新定义,这个看起来有些怪,因为在很多其他语言里这样是行不通的。

    实例五:

    <script type="text/javascript">

           function test(){

                  i = 1;

           }

           test();

           // 弹出内容为 1 的提示框

           alert(window.i);

    </script>

    分析:

    如果对一个没有初始化的变量进行赋值操作,那么这个变量会作为全局变量。

    实例六:

    <script type="text/javascript">

           window.onload = function(){

                  var i = 1;

                  function test(){

                         alert(i);

                  }

                  // 弹出内容为 1 的提示框

                  test();

           }

    </script>

    分析:

    内部函数可以访问外部函数的变量,这个就引出了一个新的概念,那就是闭包。

    闭包

    什么是闭包呢,简单的说就是一个函数 A ,它的内部函数 B 可以访问 A 内定义的变量,即使函数 A 已经终止。下面通过实例进行了解。

    实例七:

    <script type="text/javascript">

           window.onload = function(){

                  var i = 1;

                  window.onunload = function(){

                         alert(i);

                  }

           }

    </script>

    分析:

    当整个页面加载完成时,会触发 onload 事件,这个onload 事件方法里给窗口的onunload 事件注册了一个方法,这个方法里用到了onload 事件方法里声明的变量,然后onload 事件方法运行结束,这时候我们点击关闭窗口,会弹出内容为1的提示框,说明onunload 的事件方法成功的调用了onload 事件方法里声明的变量。

    为了进一步了解闭包的特性,看下面的例子

    实例八:

    <script type="text/javascript">

           function initX(oarg){

                  // 定义一个变量

                  var x = oarg;

                  // 定义一个显示变量的方法

                  var funGet = function(){

                         alert(x);

                  }

                  // 定义一个对变量进行修改的方法

                  var funSet = function(iarg){

                         x = iarg;

                  }

                  // 返回这两个方法

                  return [funGet,funSet];

           }

           // 运行一个方法实例,返回值为包含 get 和 set 方法的数组

           var funArr = initX(1);

           // 得到 get 方法

           var funGet = funArr[0];

           // 得到 set 方法

           var funSet = funArr[1];

           // 运行 get 方法,显示initX方法实例内的 x 变量,结果为 1

           funGet();

           // 运行 set 方法,对initX方法实例内的 x 变量进行赋值

           funSet(2);

           // 运行 get 方法,显示initX方法实例内的 x 变量,结果为 2

           funGet();

    </script>

    分析:

    当内部函数对外部函数定义的变量进行调用时,实际上引用的是这个变量的内存块,所以当我们调用内部函数时,引用的变量值是当前这个变量的实际内容。

    闭包功能虽然强大,但是如果不注意,它也会给我们带来困扰。看下面的例子。

    实例九:

    <button id="main">run</button>

    <script type="text/javascript">

    (function(){

           var obj = document.getElementById("main");

           var funArr = ['onclick','onkeypress'];

           for(var i=0; i<funArr.length; i++){

                  var temp = funArr[i];

                  obj[temp] = function(){

                         alert(temp);

                  }

           }

    })();

    </script>

    写代码的原意是给 id 是 main 的按钮注册点击事件和按键事件,事件的内容是分别弹出事件名称的提示框。但是结果有点匪夷所思,两个事件的提示框全是 onkeypress,根据闭包的原理,我们仔细分析,就会发现当两个事件方法被调用时 temp 变量 指向的是 funArr[1] 的内容,我们可以这样修改来解决这个问题:

    <button id="main">run</button>

    <script type="text/javascript">

    (function(){

           var obj = document.getElementById("main");

           var funArr = ['onclick','onkeypress'];

           for(var i=0; i<funArr.length; i++){

                  (function(){

                         var temp = funArr[i];

                         obj[temp] = function(){

                                alert(temp);

                         }

                  })();

           }

    })();

    </script>

    把 for 循环内的代码放入一个函数内,这样,每循环一次都会产生一个函数实例,让函数实例记录 funArr 数组中的每个值,这样就避免了上面碰到的问题。

    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fusang318/archive/2009/08/08/4423265.aspx

  • 相关阅读:
    WebClient 非阻塞客户端 RestTemplate 阻塞式客户端
    微服务网关---调用其他微服务
    复习下comparable和comparator以及比较
    关于InitializingBean的用法、应用
    Scheduled(cron = "")
    windows查看进程方法(老是忘只能写了)
    vue 控件component
    vue 过滤器的使用实例
    vue基础
    日志脱敏工具
  • 原文地址:https://www.cnblogs.com/luluping/p/1657831.html
Copyright © 2020-2023  润新知