javascript的内存空间:栈内存和堆内存

在JS中,每一个数据都需要一个内存空间。内存空间又被分为两种,栈内存(stack)与堆内存(heap)。

基础数据类型与栈内存

1.JS中的基础数据类型

常见的基本数据类型:(基本数据类型又称为常量)

  Number、String 、Boolean、Null和Undefined。基本数据类型是按值访问的,因为可以直接操作保存在变量中的实际值

这些值都有“固定的大小”,往往都保存在"栈内存"中(闭包除外),由系统自动分配存储空间。我们可以直接操作保存在栈内存空间的值,因此基础数据类型都是按值访问。

数据在栈内存中的存储与使用方式类似于数据结构中的堆栈数据结构,遵循"后进先出"的原则。

基础数据类型: NumberStringNullUndefinedBoolean

复习一下,此问题常常在面试中问到,然而答不出来的人大有人在 ~ ~

要简单理解栈内存空间的存储方式,我们可以通过类比乒乓球盒子来分析。如下图左侧。

这种乒乓球的存放方式与栈内存中存储数据的方式如出一辙。处于盒子中最顶层的乒乓球5,它一定是最后被放进去,但可以最先被使用。而我们想要使用底层的乒乓球1,就必须将上面的4个乒乓球取出来,让乒乓球1处于盒子顶层。这就是栈空间先进后出,后进先出的特点。图中已经详细的表明了栈空间的存储原理。

2.引用数据类型与堆内存

引用类型数据:

  也就是对象类型Object type,比如:Object 、Array 、Function 、Data等。

与其他语言不通,JS的引用数据类型,比如数组Array,它们值的"大小是不固定"的。引用数据类型的值是保存在堆内存中的对象。Java不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以粗浅地理解为保存在栈内存中的一个地址,该地址与堆内存的实际值相关联。

3.基本数据类型与引用数据类型的区别在于大小是否固定。

4.要简单理解堆内存空间的存储方式,我们可以通过书架与书进行类比。

书虽然也有序的存放在书架上,但是我们只要知道书的名字,我们就可以很方便的取出我们想要的书,而不用像从乒乓球盒子里取乒乓一样,非得将上面的所有乒乓球拿出来才能取到中间的某一个乒乓球。好比在JSON格式的数据中,我们存储的key-value是可以无序的,因为顺序的不同并不影响我们的使用,我们只需要关心书的名字。

为了更好的搞懂栈内存与堆内存,我们可以结合以下例子与图解进行理解。

var a1 = 0; // 栈

var a2 = 'this is string'; // 栈

var a3 = null; // 栈

var b = { m: 20 }; // 变量b存在于栈中,{m: 20} 作为对象存在于堆内存中

var c = [1, 2, 3]; // 变量c存在于栈中,[1, 2, 3] 作为对象存在于堆内存中

a1,a2,a3都是固定的值,他们都是基本数据类型。b和c都不是固定的值,同时使用栈内存和堆内存。

 

上例变量的内存分配情况图解

因此当我们要访问堆内存中的引用数据类型时,实际上我们首先是从栈中获取了该对象的地址引用(或者地址指针),然后再从堆内存中取得我们需要的数据。

理解了JS的内存空间,我们就可以借助内存空间的特性来验证一下引用类型的一些特点了。

在前端面试中我们常常会遇到这样一个类似的题目

// demo01  基本数据类型

var a = 20;

var b = a;

b = 30;

// 这时a的值是多少? 

解答:a的值为20,将a的值赋值给b,则b的值为20,后又改变b的值为30,a的值不受影响,所以a的值仍为20.

// demo02   引用数据类型

var m = { a: 10, b: 20 };

var n = m;

n.a = 15;

// 这时m.a的值是多少

解答:数组是引用数据类型,将数组m赋值给数组n,则实际上n和m在堆内存中访问到的具体对象实际上是同一个,则当 数组n里面的任意值发生改变时,整个数组会改变,由于n和m对应的是同一个数组,则数组m的值发生同样的改变,所以m.a=15.

demo01图解:

在栈内存中的数据发生复制行为时,系统会自动为新的变量分配一个新值。var b = a执行之后,a与b虽然值都等于20,但是他们其实已经是相互独立互不影响的值了。具体如图。所以我们修改了b的值以后,a的值并不会发生变化。

 

demo02图解

在demo02中,我们通过var n = m执行一次复制引用类型的操作。引用类型的复制同样也会为新的变量自动分配一个新的值保存在栈内存中,但不同的是,这个新的值,仅仅只是引用类型的一个地址指针。当地址指针相同时,尽管他们相互独立,但是在堆内存中访问到的具体对象实际上是同一个。如图所示。

因此当我改变n时,m也发生了变化。这就是引用类型的特性。

原文地址:https://www.cnblogs.com/panzai/p/12421261.html