一、堆栈的概念

在计算机领域中,堆栈是两种数据结构。

  • 堆:队列优先,先进先出;由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
  • 栈:先进后出;动态分配的空间 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。

二、js的数据类型

js的数据类型主要分为两种:基本类型值和引用类型值。

  • 基本类型值 有5种:undefined,null,boolean,number,string。这五种数据类型是按值访问的,是存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配。
var str1 = "I am string",
    num1 = 10,
    bool1 = true,
    u1 = undefined,
    n1 = null;
//复制变量值
var str2 = str1,
    num2 = num1,
    bool2 = bool1,
    u2 = u1,
    n2 = n1;
//修改变量值
str2 = "Are you new";
num2 = 20;
bool2 = false;

javascript 数据结构 图 js基本数据结构_javascript 数据结构 图


可以看到,基本类型值的复制是值的传递,赋值以后二者再无关联,修改其中一个不会影响另一个。


  • 引用类型值: 5种基本类型值以外的数据类型都可以看做是引用类型值,比如array,object等,是保存在堆内存中的对象。js不允许直接访问堆内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际是在操作对象的引用而不是实际的对象,是按地址访问的。
var obj1 = {
    a: "test a"
},  arr1 = [2, 5, 6];

var obj2 = obj1,
    arr2 = arr1;
//修改变量值
obj2.a = "change value";
arr1[1] = 48;

javascript 数据结构 图 js基本数据结构_深拷贝_02

可以看到,直接传递引用类性值的时候,传递的只是引用,二者指向同一块内存,所以修改其中一个,必然会引起另一个变量的变化。
在日常的使用中,我们把对象赋值给一个变量时,通常希望得到的是一个跟原对象无关的副本,修改新的变量不影响原对象,因此就有了浅拷贝和深拷贝。

三、浅拷贝和深拷贝

简单的说,浅拷贝就是只将对象 最外层 的键值复制为一个新的对象,而深拷贝则会 递归复制所有的层 ,直到该键的值为基本类型值。 再简单点说 ,经过浅拷贝后,新旧变量可能还会有所关联(既然说了是可能还有所关联,那也可能毫无关联吧,这里的关键就在于原对象的复杂程度了);而经过深拷贝后,理论上,新旧变量再无关联。 注意 ,在进行深拷贝时,层级不宜过多。所以,一般的深拷贝也并不是绝对毫无关联的。

var obj = {
  a: "a is a",
  arr: [ 1, 2, 3]
}, obj1 = { ...obj },  //假装这里是个浅拷贝

obj2 = JSON.parse(JSON.stringify(obj));  //假装这里是深拷贝。

obj1.a = "value a";
obj1.arr[0] = 66;

javascript 数据结构 图 js基本数据结构_深拷贝_03

可以看到,当原对象的值为 基本类型值 时,浅拷贝和深拷贝并没有区别;而当原对象的某些值为 引用类型值 时,如果修改变量的值,浅拷贝会改变原对象的值,而深拷贝则不会。


说了这些以后,不知道大家对js的数据结构有没有理解得更深刻一点呢???^_^

参考:
《JavaScript高级程序设计(第3版)》