ECMAScript 变量可能包含两种不同的数据类型的值,基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型值指由多个值构成的对象。
在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。
常用的5种基本数据类型:Undefined、Null、Boolean、Number和String。它们都是按值访问的。
1. 定义变量
比如:
var person = new Object(); person.name = "hello"; alert(person.name);
基本类型的值不能添加属性,尽管这样做不会导致任何错误。比如:
var name = "Nicholas"; name.age = 20; alert(name.age); //undefined
2. 变量的复制
var num1 = 10; var num2 = num1;
看到上面的例子,是把一个变量num1 复制给另一个变量num2。num2的值只是num1中的10的一个副本,这2个变量可以参与任何操作而不会相互影响。
当变量间复制引用类型的值时,就有不同之处。这个副本实际是一个指针,指向存储在堆中的一个对象。复制结束后两个变量实际上将引用同一个对象。因此,改变其中一个变量就会影响另一个变量。如下面的例子:
var obj1 = new Object(); var obj2 = obj1; obj1.name = "Nicholas"; alert(obj2.name); //Nicholas
3. 执行环境及作用域
执行环境(execution context) 是javascript最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object)。
全局执行环境处在最外围,在Web浏览器中我们认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。当某个执行环境中所有代码执行完毕后,该环境被销毁,保存在其中的所有变量或函数定义也随之销毁。
每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入到一个环境栈中。而在函数执行后,栈将其环境弹出,把控制权返回给之前的执行环境。
当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途是保证对执行环境有权访问的变量和函数的有序访问。作用域链的前端始终是当前执行代码所在环境的变量对象,如果这个环境是函数,那么将其活动对象(activation object) 作为变量对象。这个活动对象即是arguments对象。作用域链的下一个变量对象则是下一个包含环境,这样一直延续到全局执行环境,那么全局执行环境的变量对象始终是最后一个对象。
var color = "blue"; function changeColor() { var anotherColor = "red"; function swapColors() { var tempColor = anotherColor; anotherColor = color; color = tempColor; //这里可以访问color、anotherColor和tempColor } //这里可以访问color和anotherColor,但不能访问tempColor swapColors(); } //这里只能访问color changeColor();
以上涉及到3个执行环境:全局环境、changeColor()和swapColors()局部环境。
全局环境中有一个全局变量color和一个函数changeColor()。changeColor()局部环境中有一个名为antherColor变量和一个名为swapColors()函数。但是它们可以访问全局环境中的变量color。swapColors()中有一个变量tempColor,该变量只能在这个环境中访问到。无论全局环境和changeColor()都无权访问tempColor。在swapColors()内部则可以访问其他两个环境中的所有变量,因为那两个环境是它的父执行环境。
4. 内存问题
javascript具有自动垃圾收集机制。常用的垃圾收集方式是标记清除(mark-and-sweep),就是当变量进入环境时,就将这个变量标记为“进入环境”。而当变量离开环境时,则将其标记为“离开环境”。垃圾收集器在运行时会找到那些被加上标记的变量并把它们视为准备删除的变量。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。
另一种垃圾收集算法是“引用计数”,这种算法思想是跟踪记录所有值被引用的次数。javascript引擎目前都不再使用这种算法。