js中变量、作用域和内存问题
基本类型和引用类型的值
基本类型值是简单的数据段,而引用类型值指那些可能由多个值构成的对象。
基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中。
引用类型的值是对象,保存在堆内存中。
包含引用类型的值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针。
动态的属性
只能给引用类型值动态的添加属性,不能给基本类型的值添加属性
复制变量值
如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。
如果从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象。
传递参数
ECMAScript中所有函数的参数都是按值传递的。
检测引用类型
确定一个值是哪种基本类型可以使用typeof操作符,而确定一个值是哪种引用类型可以使用instanceof操作符。
instanceof操作符
语法:
result=variable instanceof constructor
返回true或false
执行环境及作用域
所有变量都存在于一个执行环境(也称作用域)当中,这个执行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量。
执行环境有全局执行环境(也称为全局环境)和函数执行环境之分;
每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;
函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其包含(父)环境,乃至全局环境;
全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据;
变量的执行环境有助于确定何时释放内存。
延长作用域链
在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。
(1)try-catch语句的catch块:会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明。
(2)with语句:会将指定的对象添加到作用域链中。
function buildUrl(){
var qs="?debug=true";
with(location){
var url=href+qs;
}
return url;
}
var buildUrl=buildUrl();
console.log(buildUrl);//file:///D:/project/this.html?debug=true
没有块级作用域
在其他类C的语言中,由花括号封闭的代码块都有自己的作用域(由ECMAScript的话来讲,就是它们自己的执行环境),但在JavaScript中,没有块级作用域。变量声明会被添加到当前的执行环境中。
垃圾回收策略
JavaScript具有自动垃圾收集机制。
标记清除式:当变量进入环境(例如,在函数中声明一个变量)时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。
引用计数式:跟踪记录每个值被引用的次数。当引用类型值的引用次数变成0时,垃圾收集器会释放那些
引用次数为零的值所占用的内存。当代码中出现循环引用现象时,“引用计数”算法就会导致问题。
性能问题
确定垃圾收集的时间间隔是一个非常重要的问题。IE7将触发垃圾收集的变量分配、字面量、或数组元素的临界值调整为动态修正。极大的提升了IE在运行包含大量JavaScript的页面时的性能。
管理内存
即优化内存占用。最佳方式:解除引用——一旦数据不再有用,最好通过将其值设置为null来释放其引用。