栈

- 后进者先出,先进者后出,简称 后进先出(LIFO),这就是典型的栈结构。
- 新添加的或待删除的元素都保存在栈的末尾,称作栈顶,另一端就叫栈底。
- 在栈里,新元素都靠近栈顶,旧元素都接近栈底。
- 从栈的操作特性来看,是一种 操作受限的线性表,只允许在一端插入和删除数据。
- 不包含任何元素的栈称为空栈。
堆
定义
- 堆数据结构是一种树状结构。它的存取数据的方式,与书架与书非常相似。我们不关心书的放置顺序是怎样的,只需知道书的名字就可以取出我们想要的书了。 好比在 JSON 格式的数据中,我们存储的 key-value 是可以无序的,只要知道 key,就能取出这个 key 对应的 value。
栈和堆的区别
- 堆是动态分配内存,大小不一,不会自动释放
- 栈是自动分配相对固定大小的内存空间,由系统自动释放
- 栈是线性结构,后进先出,易管理
Javascript中的栈与堆
- Javascript中的Boolean、Null、Undefined、Number、String、Symbol都是基本类型数据,保存在栈内存中,有固定的大小,通过按值访问,并由系统自动分配和自动释放。
- Javascript中的Object、Array、Function、RegExp、Date是引用类型数据,保存在堆内存中,大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象,Javascript不允许直接访问对内存中的位置,因此操作对象时,实际操作的是对象的引用
例如
let a = 12;//基本类型
let string = 'this is string';//基本类型
let boolean = false;//基本类型
let obj = {a: 'aa', b: 'bb'};//基本类型
let array = [1, 2, 3];//基本类型
基本类型的复制
let a = 20;
let b = a;
b = 30;
console.log(1); //30
- 基本类型的数据发生复制时,系统会自动为新的变量分配一个新值,相互独立,互不影响。
引用类型的复制
let obj = {a: 5, b: 10};
let copyObj = obj;
copyObj.a = 20;
console.log(obj.a);//20
- 引用类型的复制,为新的变量分配一个新的值,保存在栈内存中,这个值仅作为引用类型的一个地址指针
- 2个变量指针指向相同
浅拷贝与深拷贝
浅拷贝:引用类型数据的复制就是浅拷贝的过程,2个数据都指向同一个内存空间。修改了其中一个值,另一个也跟着改变。
深拷贝:复制得到的访问地址指向不同的内存空间。修改其中一个值,另一个不会改变。
数组的深拷贝
- 循环
function copy(arr) {
let temp = [];
for (let i = 0; i < arr.length; i++) {
temp.push(arr[i])
}
return temp;
}
let arr = [1, 2, 3, 4];
let copyArr = copy(arr);
copyArr[0] = 10;
console.log(arr, copyArr) //[1,2,3,4] [10,2,3,4]
- slice()方法
let arr2 = [1, 2, 3, 4];
let sliceArr = arr2.slice(0);
sliceArr[0] = 11;
console.log(arr, sliceArr) //[1,2,3,4] [11,2,3,4]
- concat()方法
let arr3 = [1, 2, 3, 4];
let concatArr = arr3.concat();
concatArr[0] = 0;
console.log(arr, concatArr) //[1,2,3,4] [0,2,3,4]
- ES6扩展运算
let arr4 = [1, 2, 3, 4];
let [...spreadArr] = [...arr4];
spreadArr[0] = 10;
console.log(arr, spreadArr) //[1,2,3,4] [0,2,3,4]
- JSON.parse与JSON.stringify
let arr5 = [1, 2, 3, 4];
let stringifyArr = JSON.parse(JSON.stringify(arr5));
stringifyArr[0] = 10;
console.log(arr, stringifyArr); //[1,2,3,4][10,2,3,4]
注意:该方法在数据量比较大时,会有性能问题。
对象的深拷贝
- 循环
function copy(obj) {
let copyObj = {};
for (let key in obj) {
copyObj[key] = obj[key];
}
return copyObj;
}
let obj = {x: 10, y: 20};
let copyObj = copy(obj);
copyObj.x = 20;
console.log(obj, copyObj) //{x:10,y:20} {x:20,y:20}
-
JSON.parse 与 JSON.stringify (原理同数组一样)
注意:进行JSON.stringify() 序列化的过程中,undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。 -
es6 扩展运算(原理同数组一样)
-
Object.assign()
let obj = {x: 10, y: 20};
let copyObj = Object.assign({}, obj);
copyObj.x = 20;
console.log(obj, copyObj) //{x:10,y:20} {x:20,y:20}
注意:Object.assign() 只能实现一维对象的深拷贝。