《JavaScript高级程序设计》第4章变量、作用域和内存问题
ECMAScript变量可能包含两种不同数据类型的值:基本类型值和引用类型值。在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。
函数的参数都是按值传递的。
typeof操作符:
是确定一个变量是字符串、数值、布尔值,还是undefined的最佳工具,但是对引用类型来说就无能为力了。
instanceof操作符:
如果变量是给定引用类型的实例,那么instanceof操作符就会返回true。
执行环境:
全局执行环境是最外围的一个执行环境。在web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。
延长作用域链:
try-catch语句的catch块;with语句;这两个语句都会在作用域链的前端添加一个变量对象。对with语句来说,会将指定的对象添加到作用域链中。对catch语句来说,会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明。
垃圾收集:
JavaScript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。这种垃圾收集机制的原理其实很简单:找出那些不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间),周期性地执行这一操作。
垃圾收集器必须跟踪哪个变量有用哪个变量没用,用于标识无用变量的策略可能会因实现而异,但具体到浏览器中的实现,则通常有两个策略:
(1)标记清除:
JavaScript中最常用的垃圾收集方式是标记清除。对将离开环境的变量进行标记。
到2008年为止,IE、Firefox、Opera、Chrome和Safari的JavaScript实现使用的都是标记清除式的垃圾收集策略,只不过垃圾收集的时间间隔互有不同。
(2)引用计数
另一种不太常见的垃圾收集策略叫做引用计数。引用计数的含义是跟踪记录每个值被引用的次数。
存在一个问题:循环引用,即使函数执行完毕,引用计数也不会为0。可以将变量设置为null,意味着切断变量与它此前引用的值之间的连接。
性能问题:
垃圾收集器是周期性运行的,而且如果为变量分配的内存数量很大,那么回收工作量也是相当大的。
IE的垃圾收集器是根据内存分配量运行的,具体一点说就是256个变量、4096个对象字面量和数组元素或64KB的字符串,达到任意一个临界值,垃圾收集器就会运行。这样有一个问题就是,如果一个脚本中包含那么多变量,那么就会频繁的运行。结果,由此引发的严重性能问题促使IE7重写了其垃圾收集例程。
在IE中,调用window.CollectGarbage(),在Opera7及更高版本中,调用window.opera.collect()都会启动垃圾收集器。
管理内存:
分配给Web浏览器的可用内存数量通常要比分配给桌面应用程序的少,这样做的目的主要是出于安全的方面的考虑,防止运行JavaScript的网页耗尽全部系统内存而导致系统崩溃。
而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据,一旦数据不再有用,最好通过将其值设置为null来释放其引用—这个做法叫做解除引用。这一做法适用于大多数全局变量和全局对象的属性,局部变量会在它们离开执行环境时自动被解除引用。
小结:
类型:
(1)基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中;
(2)引用类型的值是对象,保存在堆内存中;
作用域:
(3)执行环境有全局执行环境和函数执行环境之分;
(4)每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;
(5)变量的执行环境有助于确定应该何时释放内存;
(6)离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除;
内存:
(7)“标记清除”是目前主流的垃圾收集算法,这种算法思想是给当前不使用的值加上标记,然后再回收其内存;
(8)另一种垃圾收集算法是“引用计数”,这种算法的思想是跟踪记录所有值被引用的次数,JS引擎目前都不再使用这种算法。