高程(第四章) 变量、做用域和内存问题

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

  • 基本数据类型是按值访问的,由于能够操做保存在变量中的实际的值javascript

基本类型值在内存中占据固定大小的空间,所以被保存在栈内存中前端

  • 引用类型的值是保存在内存中的对象。JavaScript不容许直接访问内存中的位置,也就是说不能直接操做对象的内存空间。在操做对象时,其实是在操做对象的引用而不是实际的对象。为此,引用类型的值是按引用的。java

以上关于引用类型的说法不严密,当复制保存着对象的某个变量时,操做的是对象的引用。但在为对象添加属性时,操做的是实际的对象
引用类型的值是对象,保存在堆内存中算法

1.1 动态的属性

不能给基本类型的值添加属性,尽管这样作不会致使任何错误函数

1.2 复制变量值

  • 从一个变量向另外一个变量复制基本类型的值,会建立这个值的一个副本指针

  • 包含引用类型值的变量实际上包含的并非对象自己,而是一个指向该对象的指针code

1.3 传递参数

ECMAScript中全部函数的参数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另外一个变量同样对象

1.4 检测类型

肯定一个值是哪一种基本类型能够使用typeof操做符,而肯定一个值是哪一种引用类型能够使用instanceof操做符ip

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的引用

解除一个值得引用并不意味着自动回收该值所占用的内存。解除引用的真正做用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收

相关文章
相关标签/搜索