zoukankan      html  css  js  c++  java
  • JavaScript中变量、作用域、内存问题

    这几天,闲的没事看看JavaScript高级编程,感觉JavaScript真的很强大,尤其是采用面向对象的编程方式。

    一.   基本类型和引用类型的值:

              ECMAScript变量可能包含两种不同数据类型的值:基本类型值和引用类型值。

             基本类型的值指的是简单的数据段,比如Undefined、Null、Boolean、Number、String,这5种基本类型是按值访问的;

             引用类型的值指的是保存在内存中的对象,在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的。

    二.传递参数:

               ECMAScript中所有函数的参数都是按值传递的,换句话说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。

               基本类型值的传递如同基本类型变量的复制一样;

               引用类型值得传递如同引用类型变量的复制一样;

    三.执行环境及作用域链:

    1. 执行环境

               执行环境(execution context) 是JavaScript中最为重要的一个概念,执行环境定义了变

               量或函数是否有权访问其他数据,决定了它们各自的行为。每个执行环境都有一个与之相关的“变量对象”,环境中定义的所有变量和函数都保存在这个对象中。虽然我们  

               编写的代码无法访问这个对象,但解析器在处理数据是会在后台使用它。

            

               全局执行环境是最外围的一个执行环境。在Web游览器中,全局执行环境被认为是Window对象,因此所有变量和函数都是作为window对象的属性和方法创建的。某个执

               行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出——例如关闭网页或游览器时才会被销

               毁)。

               执行环境类型总共两种:

              (1)     全局执行环境(window);

              (2)     局部执行环境(函数function);

    1. 作用域链

              当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的的前端,始终都

              是当前执行的代码所在环境的变量对象。作用域链中的下一个变量对象来自包含(外部)环境,而在下一个变量对象则来自下一个包含对象。这样,一直延续到全局执行

              环境,全局执行环境的变量对象始终都是作用域链中的最后一个对象。

              例如: 

    1. var color = "blue";  
    2.   
    3.   
    4.   
    5. function changeColor(){  
    6.   
    7.          var anotherColor = "red";  
    8.   
    9.          function swapColors(){  
    10.   
    11.                   var tempColor = anotherColor;  
    12.   
    13.                   anotherColor = color;  
    14.   
    15.                   color = tempColor;  
    16.   
    17.                   //这里可以访问color、anotherColor和tempColor  
    18.   
    19.          }  
    20.   
    21.          //这里可以访问color和anotherColor,但不能访问tempColor  
    22.   
    23.          swapColors();  
    24.   
    25. }  
    26.   
    27. //这里只能访问color  
    28.   
    29. changeColor();  

               先画一个作用域链示例图:

              

              上图中,矩形表示特定的执行环境。其中,内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。每个环境都可以向上搜索作用域链,以查询变量和函数名。任何环境都不能通过向下搜索作用域链而

              进入另一个执行环境。

              以上代码共涉及3个执行环境:全局环境、changeColor()的局部环境和swapColors()的局部环境。

             全局执行环境中有一个变量color和一个函数changeColor();

             changeColor()局部环境中有一个变量anotherColor和一个函数swapColors(),但它也可以访问全局环境中的变量color,

             swapColors()局部环境中有一个变量tempColor,该变量只能在该环境中访问到,无论是全局环境还是changeColor()的局部环境都无权访问tempColor。然而,在swapColors()内部,则可以访问其他两个环境中的所有变量,因为那两个环境是它的

             父执行环境。

    四.延长作用域链

             当执行流进入下列任何一个语句时,作用域链将得到延长:

             1) try-catch语句的catch块

             2) with语句

            此两个语句会在作用域链的前端添加一个变量对象。对with来说,其变量对象中包含着指定对象的所有属性和方法所作的变量声明;对catch来说,其变量对象中包含的是被抛出的错误对象的声明。这些变量对象都是只读的,因此在with和catch语句

            中声明的变量都会被添加到所在执行环境的变量对象中。

             例如: 

    1. (function(){  
    2.   
    3.          with(location){  
    4.   
    5.                   var myhref = href; //在with语句中声明一个myhref变量  
    6.   
    7.          }  
    8.   
    9.          // 居然被添加到当前执行函数的执行环境中了,看来with语句中指定的对象时只读的  
    10.   
    11.          console.log(myhref);  
    12.   
    13. })();  

    五.没有块级作用域

    1. 什么是块级作用域?

                 在C/C++/Java中,由花括号封闭的代码都有自己的作用域(如果使用ECMAScript的话来讲,就是它们自己的执行环境)。

                 例如: 

    1. if(true){  
    2.   
    3.     //块级作用域  
    4.     var color = “blue”;  
    5.   
    6.  }  
    7.   
    8. alert(color);  

             对于有块级作用域的语言来说,if语句中所定义的变量,只会存在于if的环境之中,color变量会在if语句执行完毕后被销毁。但是,在JavaScript中,if语句中的变量声明会将变量添加到当前的执行环境中(这里是全局环境)。

    1. 声明变量

                 使用var声明的变量会自动被添加到最接近的环境中。如果没有使用var声明变量,该变量会自动被添加到全局环境中。

                例如: 

    1. function add(num1,num2){  
    2.   
    3.          //没有使用var声明变量,自动被添加到最接近的环境中(全局执行环境)  
    4.   
    5.          sum = num1 + num2;  
    6.   
    7.          return sum;  
    8.   
    9. }  
    10.   
    11. var result = add(10,20);  
    12.   
    13. //这里访问sum成功,说明该变量在全局执行环境中  
    14.   
    15. console.log(sum);  

             不声明而直接初始化变量时一个常见的错误做法,这样可能会导致意外。

    1. 查询标识符 
    1. var color = "blue";  
    2.   
    3.         
    4.   
    5.        function changeColor(){  
    6.   
    7.              function swapColors(){  
    8.   
    9.                     return color;  
    10.   
    11.              }  
    12.   
    13.              return  swapColors();  
    14.   
    15.        }  
    16.   
    17. console.log(changeColor());  

           先画一个查询标识符示意图:

          

       

          调用本例中的changeColor()时会引用变量color,为了确定变量color的值,将开始一个3步的

          搜索过程,首先,搜索swapColors()的变量对象,查找是否包含一个名为color的标识符。在没有找到的情况下,继续搜索下一个变量对象(changeColor()的变量对象),如

         果没有继续搜索下一个变量对象(也就是全局环境的变量对象),然后在这里找

          到了名为color的标识符,搜索过程宣告结束。

    六.管理内存

             优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据,一旦数据不再使用,最好通过将其设置为null来释放其引用——这个做法叫做“解除引用”

             例如: 

    1. function createPerson(name){  
    2.   
    3.     var localPerson = new Object();  
    4.   
    5.           localPerson.name = name;  
    6.   
    7.           return localPerson;  
    8.   
    9.  }  
    10.   
    11.   
    12.   
    13.  var globalPerson = createPerson("Admin");  
    14.   
    15.   
    16.   
    17.  //手工解除globalPerson的引用  
    18.   
    19.  globalPerson = null;  

            以上代码中,由于变量localPerson 在createPerson()函数执行完毕后就离开了其执行环境,因此,无需我们显式地为它解除引用。但是对于全局变量globalPerson而言,则需要我们在不使用它的时候手工为它解除引用。

  • 相关阅读:
    关于 数据库中 读写 Blob 字段的正确做法。
    C# wave mp3 播放器探寻
    公布Delphi热键注册源码
    Windows 下 Eclipse 集成开发环境演绎
    VS2012 MSHA 文件制做程序
    Erlang 学习笔记 (二) Debugger工具的使用
    Excel里数字列号转换为字符标签列
    串或序列的rotate操作
    64K动画技术剖析:Mod音乐的制作和使用
    64K动画 技术剖析之:Metaball
  • 原文地址:https://www.cnblogs.com/web100/p/js-param-score.html
Copyright © 2011-2022 走看看