js红宝书笔记系列:第4章 变量,作用域和内存

186 阅读4分钟

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

  1. 基本类型是指简单的数据段,引用类型指的是那些由多个值构成的对象,基本类型有Undefined,Null,Boolean,Number,String,它们是按值访问,因为可以操作保存在变量中实际的值
  2. 引用类型是按引用访问的,它的值是保存在内存中的对象,不允许直接访问内存中的位置
  3. 不能给基本类型的值添加属性 ,引用类型才可以
var name = 'darcy'
darcy.age = 24
alert(name.age) // undefined

var person = new Object()
person.age = 24
alert(name.age) // 24
  1. 基本类型中,值的复制是完全独立的。如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到新分配的位置上

    1. var num1 = 5;
      var num2 = num1; // num2的5与num1的5是完全独立的,是num1中5的一个副本,这2个变量可以参与任何操作而不会相互影响
      

  1. 引用类型则不同,当从一个变量向另一个变量复制引用类型的值时,同样的也会将存储在变量对象中的值复制一份,放到新变量分配的空间中。不同的是,这个值的副本实际上只是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,2个变量实际上引用同一个对象。因此,改变其中一个变量,就会影响另一个变量,见例:

    1. var obj1 = new Object();
      var obj2 = obj1;
      obj.name = 'darcy';
      alert(obj2.name); // 'darcy'
      
  2. obj1保存了一个对象的新实例,然后被复制到了obj2,即obj1和obj2都指向同一个对象。这样,当为obj1添加name属性后,可以通过obj2来访问该属性,因为他们引用的都是同一个对象,见图

传递参数

  • 所有函数的参数都是按值传递的,参数实际上是函数的局部变量。当函数的变量是一个对象时,对象也是按值传递,以下是关于参数为对象的2个例子
  • 第一个例子
function setName(obj) {
obj.name = 'darcy';
}
var person = new Object();
setName(person);
alert(person.name); // 'darcy'

创建了一个对象,对象保存在变量person中,然后被传递到setName()被复制给了obj,在函数内部,obj和person引用同一个对象,内部添加属性后,外部的person也有所反映了,因为person指向的内存只有一个。

// 第2个例子
function setName(obj) {
obj.name = 'darcy';
obj = new Object();
obj.name = 'lx';
}
var person = new Object();
setName(person);
alert(person.name); // 'darcy'

和上面相比,多了2步,重新定义了一个对象,接着为对象定义了一个带有不同值的属性。person传递给了setName(),name的属性被设置为“darcy”。然后,又将一个新对象赋给obj,同时name的属性设置为“lx”。如果person是按引用传递的,那么persopn就会自动修改为'lx'的新对象。但是alert出来的还是darcy, 这说明在函数内部修改了参数的值,但原始的引用仍然不变。实际上,当在函数内部重写obj时,这个变量引用的就是一个局部对象了,而这个局部对象会再函数执行完毕后,立即被销毁

执行环境及作用域


  1. Js没有块级作用域

  2. 查询标识符从里到外,从局部到全局,如果局部和全局的变量名相同,从里面已经搜索到了局部变量,则搜索停止

  3. var color = 'blue';
    function getColor(){
    var color = 'red';
    }
    alert(getColor()) // red  里面搜索到了同名的,停止
    

垃圾收集


标记清除 :垃圾收集器在运行时给存储在内存的所有变量都加上标记,然后它会去掉环境中的变量以及被环境中的变量引用的变量的标记,再加上被加上标记的变量是准备删除的变量,最后垃圾收集器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存

引用计数:(不太常见)跟踪记录每个值没引用的次数,当声明变量并将一个引用类型值赋给变量时,值的引用次数+1,又被赋值,则又+1。相反,如果包含对这个值的引用的变量又取得了另外一个值,这个值-1,当变成0时,就说明没有办法再访问了,就能回收了。有个严重问题:多链路引用会导致window.collectGarbage()方法会立即执行垃圾收集