首页 > 代码库 > 变量、作用域和内存问题

变量、作用域和内存问题

1 基本类型和引用类型的值

ECMAScript可能包含两种不同数据类型的值:

  • 基本类型值——简单的数据段
  • 引用类型值——可能由多个值构成的对象

1.1 动态的属性

可以动态地为引用类型值添加或删除属性和方法:

var person = new Object();
person.name = "Nicholas";
alert("person.name");        //"Nicholas"

不能给基本类型添加属性,尽管不会导致任何错误:

var name = "Nicholas";
name.age = 27;
alert("name.age");            //undefined

1.2 复制变量值

基本类型:创建的是原来变量的一个副本,是两个完全独立的变量,修改其中之一不会影响另一个。

var num1 = 5;
var num2 = num1;
num1 = 10;
alert("num1");            //10
alert("num2");            //5

引用类型:创建的是对象的指针,指向原来的变量指向的对象。改变其中一个变量会影响另一个变量。

var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name);                //"Nicholas"

1.3 传递参数

ECMAscript中所有函数的参数都是按值传递的。基本类型的传递和基本类型复制一样,而引用类型传递即和引用类型复制一样。

基本类型:

function addTen(num) {
    num += 10;
    return num;
}
var count = 20;
var result = addTen(count);
alert(count);                      //20      
alert(result);                     //30

 

 引用类型:

function setName(obj) {
    obj.name = "Nicholas";           //这里的obj为传入的参数的一个(指针)副本,其指向传入参数指向的对象,可以用其来为其指向的对象添加属性。
}
var person = new Object();
setName(person);
alert(person.name);            //"Nicholas
1 function setName(obj) {
2     obj.name = "Nicholas";             //obj指向的对象与传入参数指向的对象相同,这里obj为其指向的对象添加了name属性
3     obj = new Object();               //obj指向了一个新的局部对象
4     boj.name = "Greg";               //为这个局部对象添加name属性
5 }                                    //脱离了作用域,obj指向的局部对象被销毁
6 
7 var person = new Object();
8 setName(person);    
9 alert(person.name);

 

检测类型:

typeof操作符:

1 var u;
2 var n = null;
3 var o = new Object();
4 
5 alert(typeof u);            //undefined
6 alert(typeof n);            //object
7 alert(typeof o);            //object

 

typeof检测函数时返回"function"。在Safari5及之前版本与chrome及之前版本用typeof检测正则表达式返回"function",因为ECMA-262规定任何内部实现了[[Call]]方法的对象在应用typeof操作符时返回"function"。

而在IE和Firefox中对正则表达式应用typeof返回“object”。

instanceof操作符:

语法: result = variable instanceof constructor 

如果变量是给定引用类型(根据它的原型链来识别)的实例,那么instanceof操作符就返回true。

2 执行环境及作用域

内部作用域可以访问外部作用域的局部变量,反之则不能。函数参数被当作变量来对待,因此其访问规则与作用域中其他变量的访问规则相同。

2.1 延长作用域链

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

  • try-catch语句的catch块
  • with语句

2.2 没有块级作用域

if语句和for语句中的变量声明会将变量添加到当前的执行环境,这点与其他类C语言不同。

 1 if (true) {
 2     var color = "blue";
 3 }          //在C、C++等语言中,此时color因离开作用域而被销毁,但是javascript中不会。
 4 
 5 alert(color);        //"blue"
 6 
 7 for (var i = 0; i < 10; ++i) {
 8     doSomething(i);
 9 }          // 在C、C++等语言中,此时 i 因离开作用域而被销毁,但是javascript中不会。
10 alert(i);            //10

变量声明:var声明的变量会被自动添加到就近环境。初始化变量没有使用var声明,变量会被自动添加到全局环境。

!!!不声明而直接初始变量是一个常见的错误做法,因为可能导致意外。建议在初始化变量之前一定要声明变量。

 

查询标识符:标识符查询是从内往外逐层查询,直到找到标识符或搜索到全局作用域为止。一旦找到标识符,立即停止搜索。内层作用域的同名变量会覆盖外层作用域的同名变量。

 

3 垃圾收集

JavaScript具有自动垃圾手机机制,通常有两种策略:

  • 标记清除:垃圾收集器在运行的时候给存储在内存中的变量都加上标记,然后去掉环境中的变量以及被环境中变量引用的变量的标记,在此之后再被标记的变量将被视为准备删除的变量。
  • 引用计数:值被引用或复制时引用计数加1,而包含对这个值的引用的变量取得另一个值时引用次数减1。当引用计数为0时内存将被释放。(不常用)

IE7垃圾回收例程工作方式:如果垃圾收集例程回收的内存分配量低于15%,则变量、字面量和元素数组的临界值会加倍。如果内存回收了85%的内存分配量,则将各种临界值重置回默认值。

 

变量、作用域和内存问题