1 基本类型和引用类型的值
基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值
基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中
引用类型的值是保存在内存中的对象。JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用的。
以上关于引用类型的说法不严密,当复制保存着对象的某个变量时,操作的是对象的引用。但在为对象添加属性时,操作的是实际的对象
引用类型的值是对象,保存在堆内存中
1.1 动态的属性
不能给基本类型的值添加属性,尽管这样做不会导致任何错误
1.2 复制变量值
从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本
包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针
1.3 传递参数
ECMAScript中所有函数的参数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样
1.4 检测类型
确定一个值是哪种基本类型可以使用typeof
操作符,而确定一个值是哪种引用类型可以使用instanceof
操作符
console.log(typeof s); //检测变量s是哪种基本类型值
console.log(colors instanceof Array); //检测变量colors是否引用类型Array
2 执行环境及作用域
每个环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它
2.1 延长作用域链
执行环境的类型总共只有两种——全局和局部(函数)
,但是还有其他办法来延长作用域链
以下两个语句都会在作用互联的前端添加一个变量对象:
try-catch语句的catch块
catch
会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明
with语句
with
语句会将指定的对象添加到作用域链中
2.2 没有块级作用域
在if
或者for
语句中定义的变量在代码块执行结束后,会存在于代码块外部的执行环境中
3 垃圾收集
3.1 标记清除
垃圾收集器在运行的时候会给储存在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量被视为准备删除的变量,原因是环境中的变量以及无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间
"标记清除"是目前主流的垃圾收集算法
3.2 引用计数
引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个值,则这个值的引用次数减1。当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来
这种引用计数策略存在一个严重的问题:循环引用
function problem(){
var objectA = new Object();
var objectB = new Object();
objectA.someOtherObject = objectB;
objectB.anotherObject = objectA;
}
上面例子中,objectA和objectB通过各自的属性互相引用,它们的引用次数永远不会是0。假如这个函数被重复多次调用,就会导致大量内存得不到回收
3.4 管理内存
一旦数据不再有用,最好通过将其值设置为null来释放其引用——这个做法叫做解除引用(dereferencing)
function createPerson(name){
var localPerson = new Object();
localPerson.name = name;
return localPerson;
}
var globalPerson = createPerson("Nicholas");
globalPerson = null; //手工解除globalPerson的引用
解除一个值得引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。