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堆内存中。
栈与堆的关系大致如图
- 栈内存:引擎执行代码时的内存空间,用来保存基本值和引用类型值的地址。
- 堆内存:用来保存一组无序且唯一的引用类型值,可以使用栈中的键名来取得。
//基本值
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]
- 左边是栈,右边是堆
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;
执行代码b=a时,栈内存会新开辟一个内存,大致如下:
此时修改a=2,对b并不会造成影响
- 引用数据类型--名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值,我们以上面的代码(浅拷贝)的为例画个图:
- 首先a这个数组在计算机存储情况如下:
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值,此时a与b在计算机中存储的情况如下:
而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝