js基本类型和引用类型小结

概念

基本类型指的是简单的数据段,String Number Undefined Null Boolean这五种,他们的值保存在栈中。引用类型指的是可能由多个值构成的对象,值保存在堆中。

为什么会有堆和栈之分呢?因为每个函数执行时都会建立自己的内存栈,调用结束就释放内存。堆内存中的对象不会随着调用的结束而销毁,只有当一个对象没有任何引用变量引用时,系统的垃圾回收机制才会回收它。

变量的赋值

对于基本类型来说,如果从一个变量A向另一个变量B赋基本类型的值,会将A的值复制一份,然后把复制后的值给B。事实上就是A,B在栈中指向不同的位置,完全不相关。

对于引用类型来说,操作对象实际上操作的是对象的引用,(当为对象添加属性的时候,操作的是实际的对象)。当将Obj赋值给newObj时,也会将存储在变量对象obj中的值复制一份到为新变量newObj分配的空间中,但是这个值的副本实际上是一个指针,指向存储在堆中的一个对象。因此改变newObj会影响到obj。

image

深拷贝与浅拷贝

浅拷贝:两个对象指向的是堆中的同一个对象,一方改变,另一个也会改变。

数组的深拷贝的实现:

如果数组中的元素是基本类型,那么slice和concat是没有问题的,但是如果数组中的元素是对象类型的话,其实这两个函数也只是一个浅复制。

concat方法返回一个新数组,它包含array的浅复制。(摘自javascript语言精粹 第8章)

  1. var newArray = array.slice(0);//这个其实是浅复制
  2. var newArray = array.contact();//之前一直理解错了,其实concat也是浅拷贝。
    1
    2
    3
    4
    5
    6
    var arr = [{name:'lily'},{name:'jack'}];
    var b = arr.concat([5,6]);
    b
    [Object, Object, 5, 6]
    arr[0].name = 'bob';
    b[0].name//输出"bob"

对象的深拷贝

  1. var newObj = Json.parse( Json.stringfy(obj) );
  2. var newObj = Object.create(obj);//把obj当做是newObj的原型进行创建
    1
    2
    3
    4
    5
    6
    7
    function clone(obj) {
    var newObj = {};
    for(var i in obj){
    newObj[obj[i]] = typeof obj[i] === 'object' ? clone(obj[i]) : obj[i];
    }
    return newObj;
    }

传递参数

基本类型传参

基本类型的传参和基本类型的赋值相同,都是复制一个临时变量。

image

因此,在函数addTen中改变的值只是一个临时变量的值,并不会影响到num本身。

引用类型传参

引用类型的传参传递的也是值,而不是引用。

image

这里,虽然是按值传递的,其实还是指向的是堆内存中唯一一个变量。

下面这个例子可以证明引用类型的参数传递是按值传递的,而不是按地址传递的。

image

这里,在全局变量中有一个person,如果是按引用传递的,那么在setName函数内部对obj的改变应该会反映到person上面,但是并不会。事实上内部新建的obj之后,这个变量引用就是一个局部变量,函数执行完了就销毁了,并不会影响到外部的person。