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;
解除引用的作用真正作用是让值脱离执行环境,以便垃圾收集器下一次运行时将其回收。