JavaScript高级程序设计学习笔记——第4章 变量,作用域和内存问题

2013-5-17 | 发布者:www.sealiu.tk

我的笔记:


 

1,ECMAScript 变量可能包含有两种不同的数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象;基本类型 值:(undefined,null,boolean,number,string),引用类型值是保存在内存中的对象;

1.1 添加属性:

  • 不能给基本类型的值添加属性,尽管这样做不会导致任何错误;

    var name="Nicholas";

    name.age=27;

    alert(name.age);     //undefined

  • 但是引用类型的值(对象)就可以;

    var person=new Object();

    person.name="Nicholas";

    alert(person.name);     //"Nicholas"

1.2 复制:

  • 如果从一个变量向另一个变量复制基本类型的值,会在变量对象中创建一个新值;

  • 当从一个变量向另一个变量复制引用类型的值时,同样会将存储的变量对象中的值复制一份放到新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,指向存储在堆中的一个对象。复制结束后两个变量实际将引用同一个对象

1.3 传递参数:

  • 向参数传递基本类型的值时:函数外部的值复制给函数内部的参数,就和吧值从一个变量复制到另一个变量一样;看下面的代码:

    function addTen(num){

            num+=10;

            return num;

    }

    var count=20;

    var result=addTen(count);

    alert(count);                     //20,没有变化

    alert(result);                     //30

     

    //这里的addTen( )有一个参数num,而参数的实际是函数的局部变量。在函数内部参数num被加上了10,但这一变化不会影响到函数外部的count变量。这是按值传递;如果是按引用传递的话,那么变量count的值也将变成30;

  • 如果使用对象,也是按值传递,但是和上面会有所不同,看下面的代码:

    function setName(obj){

                 obj.name="Nicholas";

    }

    var person=new Object( );

    setName(person);

    alert(person.name);                       //"Nicholas"

     

    //上面代码中创建了一个对象,并保存在了person变量中,传递到setName()函数中就复制给了obj;在函数内部obj和person引用的是同一个对象。所以当函数内部为

    obj添加name属性后,函数外部的person也将有变化;因为person所指向的对象在内存中只有一个而且是全局变量。但是这些不足已说明这个对象是按值传递的,看下面的代码:

    function setName(obj){

         obj.name="Nilcholas";

         obj=new Object();

         obj.name="Greg";

    }

    var person=new Object();

    setName(person);

    alert(person.name);                 //"Nilcholas"

     

    //添加了两行代码:一行为obj重新定义了一个对象,另一行代码为对象定义了一个带有不同值的name属性。如果person是按引用传递的,那么person就会被修改为指向其name属性值为“Greg”的新对象。结果证明这是错的!

1.4 检测类型

  • typeof 操作符(第3章),typeof是确定一个变量时字符串,数字,布尔值,还是undefined的最佳工具。但是在检测应用类型的值的时候,这个操作符用 处不大。通常,我们并不是想知道某个值时对象,而是想知道是什么类型的对象。为此ECMAScript提供了instanceof操作符

  • 语法:result=variable instanceof constructor

  • 举例:

           alert(person instanceof Object);     //变量person是Object么?

           alert(person instanceof Array);       //变量person是Array么?

           alert(person instanceof RegExp);   //变量person是RegExp(正则表达式)么?

 


 

2.执行环境及作用域,和C++语言的变量作用域类似。每个函数都会有自己的执行环境(有时也称为“环境”)。

全局环境,局部环境(每个函数的),在全局环境定义的变量是全局变量(可以在程序的任何地方访问),在局部环境定义的变量是局部变量(只能在定义它的那个局部环境中访问)。

2.1 延长作用域链的两个方法:

  • try-catch语句的catch块;
    try                                                 
    {                                            
     // 可能会引发错误的一些代码          
    }                                             
    catch (err:Error)                       
    {                                             
    // 用于响应错误的代码              
    }                                            
    finally                                       
    {                                           
    //其余需要运行的代码。                
    }                                           

将有可能产生错误的语句括在一起,放入try语句块。如果在try语句块中发生异常,FlashPlayer会创建一个错误对象,并将该Error对象派发至第一个可用的catch块。

catch 语句快提供对错误的处理。如果没有try语句,或者try语句没有出现错误,则catch语句不会被引发。如果在try语句块的其中某个 语句中检测到错 误,则会执行附加到该try语句的catch语句。catch语句可以并列使用,即在一个try语句块之后,存在多个catch语句块,以 处理不同的错 误对象。

 

  • with语句

在 With 语句块中,凡是 JavaScript 不识别的属性和方法都和该语句块指定的对象有关。With 语句的语法格式如下所示:

      With Object {
      Statements
      }
      对象指明了当语句组中对象缺省时的参考对象,这里我们用较为熟悉的 Document 对象对 With 语句举例。例如 当使用与 Document 对象有关的 write( )或 writeln( )方法时,往往使用如下形式:
      document.writeln(”Hello!“)
      如 果需要显示大量数据时,就会多次使用同样的 document.writeln()语句,这时就可以像下面的程序那样,把所有以 Document 对象为参考对象的语句放到With 语句块中,从而达到减少语句量的目的。下面是一个With 语句使用的例子:

 1  <html>
 2 <head>
 3         <title>JavaScript Unleashed</title>
 4 </head>
 5 <body>
 6         <script type="text/javascript">
 7         8             with(document){
 9               write("您好 !");
10               write("<br>这个文档的标题是 : \"" + title + "\".");
11               write("<br>这个文档的 URL 是: " + URL);
12               write("<br>现在您不用每次都写出 document 对象的前缀了 !");
13            }
14         
15         </script>
16 </body>
17 </html>

 


这样,您在使用 document 的方法和属性时就可以去掉 Document 前缀。

2.2 JS没有块级作用域,不同于C,C++,Java

  • if(true){

          var color="blue";

          }

          alert(color);     //blue

          但C,C++或Java这种有块级作用域的语言来说,color会在if语句执行完毕后被销毁。但是JavaScript不会。

  • 如果初始化变量时没有使用var声明,该变量就是全局变量。否则是局部变量;
1 function add(num1,num2){
2 var sum=num1+num2;
3 return sum;
4 }
5 
6 var result=add(10,20);    //30
7 alert(sum);        //由于sum不是有效的变量,出错

 

 

1 function add(num1,num2){
2 sum=num1+num2;
3 return sum;
4 }
5 
6 var result=add(10,20);    //30
7 alert(sum);                     //30

 

  • 查询标识符的方向是从局部环境向上到全局环境(搜索过程冲作用域链的前端开始,向上逐级查询给定名字匹配的标识符)
 1 var color="blue";
 2 function getColor(){
 3 return color;
 4 }
 5 alert(getColor());    //blue
 6 
 7 //=====================
 8 
 9 var color="blue";
10 function getColor(){
11 var color="red";
12 return color;
13 }
14 alert(getColor());    //是red  不是blue

 


3. 垃圾收集   

JavaScript具有自动垃圾收集机制,而在C++语言中需要手工跟踪内存的使用情况。

JS垃圾收集的两种方式:

  • 标记清除
  • 应用计数

由于分配给Web浏览器的可用内存数量通常要比非配给桌面应用程序的少,所以确保占用最少内存让页面获得更好的性能,可以通过手工接触引用(将其值设置为null)来释放其引用。

1 function creatPerson(name){
2      var localPerson=new.Object();
3      localPerson.name=name;
4      return localPerson;
5 }
6 var globalPerson=creatPerson("Nicholas");
7 //手工解除globalPerson的引用
8 globalPerson=null;

 

解除引用的作用真正作用是让值脱离执行环境,以便垃圾收集器下一次运行时将其回收。

 

 

 

 

 

posted @ 2013-05-17 16:05  SEA Liu  阅读(190)  评论(0编辑  收藏  举报