JS数据类型与浅拷贝

656 阅读3分钟

JavaScript数据类型:

值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。

引用数据类型:对象(Object)、数组(Array)、函数(Function)、Map

栈和堆

栈(stack):栈会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间。 基本类型:String,Number,Boolean,Null,Undefined,Symbol

堆(heap):动态分配的内存,大小不定也不会自动释放,存放引用类型,指那些可能由多个值构成的对象,保存在堆内存中,包含引用类型的变量,实际上保存的不是变量本身,而是指向该对象的指针。 引用类型:Function,Array,Object 区别

  • 栈:所有在方法中定义的变量都是放在栈内存中,随着方法的执行结束,这个方法的内存栈也自然销毁。

优点:存取速度比堆快,仅次于直接位于CPU中的寄存器,数据可以共享; 缺点:存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。

  • 堆:堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(参数传递)。创建对象是为了反复利用,这个对象将被保存到运行时数据区。

栈和堆的溢出

  • 栈:可以使用递归调用方法,这样随着栈深度的增加,JVM维持着一条长长的方法调用轨迹,当内存不够分配,产生栈溢出。
  • 堆:循环创建对象,通俗点就是不断的new 一个对象。

下面来看看传值和传址的区别

  • 其实这两者区别就是基本类型和引用类型的区别,话不多说看栗子
var a = [1,0,9,8,7];
   var b = a;
   var c = a[0];
   console.log(b);     //[1,0,9,8,7]
   console.log(c);     //1
   //改变数值
   b[1] = 3;
   c = 5;
   console.log(b[1]);  //3
   console.log(a[0]);  //1   
   console.log(a);  //[1,3,9,8,7] 
  • 因为a是数组,是引用类型,赋给b的时候传的是栈中的地址,不是堆内存中的对象,c仅仅是从a堆内存中获取的一个数据值,并保存在栈中,所以b修改的时候,会根据地址回到a堆中修改,c则直接在栈中修改,并且不能指向a堆内存中。

栈与堆的关系大致如图

  • 栈内存:引擎执行代码时的内存空间,用来保存基本值和引用类型值的地址。
  • 堆内存:用来保存一组无序且唯一的引用类型值,可以使用栈中的键名来取得。

461976-20180823211511434-1707579794.png

//基本值
var a = 1;
var b = a;
a = 2;
console.log(a); //输出:2
console.log(b); //输出:1
 
//引用值
//变量 c 和 d 指向堆中的同一个数组
var c = [0, 1, 2];
var d = c;
c[0] = 5;
console.log(c); //输出:[5, 1, 2]
console.log(d); //输出:[5, 1, 2]
  • 左边是栈,右边是堆 201944163413499.jpg

JS浅拷贝(目前的学习基本没有接触什么深拷贝,会在以后的学习中添补)

  • 先举一个浅拷贝的例子
var a=[0,1,2,3,4];
    b=a;
console.log(a===b);  // true
    a[0]=1;
console.log(a,b);    //[ 1, 1, 2, 3, 4 ] [ 1, 1, 2, 3, 4 ]
  • 基本类型--名和值都存储在栈内存中,例如var a=1;

1213309-20171124130901890-511917244.jpg

执行代码b=a时,栈内存会新开辟一个内存,大致如下:

1213309-20171124131822437-430949998.jpg

此时修改a=2,对b并不会造成影响

  • 引用数据类型--名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值,我们以上面的代码(浅拷贝)的为例画个图:
  1. 首先a这个数组在计算机存储情况如下:

1213309-20171124133428359-1292133331.jpg

当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值,此时a与b在计算机中存储的情况如下:

1213309-20171124133647796-1390255671.jpg

而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝

1213309-20171124133934328-67216865.jpg