这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战
前言
其实我对这个东西(堆/栈)也挺模糊,翻阅了好多文章,想着总结一篇,如果理解有误请指出
栈
大致说一下什么是
栈
, 看文章都说他先进后厨,能够直接修改的就是栈
,栈
是自动分配相对固定大小的内存空间,并由系统自动释放,栈内存变量基本上用完就回收了。
比如:数值(Number)
、字符串(String)
、null(Null)
、undefined
、Boolean
个人理解栈
就是,每个栈
都是独立的相互不影响,每个栈
都会开辟新的空间。
关于栈的代码示例:
数值类型
//示例1
let a = 123;
let b = a;
a = 6;
console.log(a,b) //输出 6 123
//示例2
let a = 123;
let b = a;
b = 1;
console.log(a,b) //输出 123 1
总结: 数值类型的更改相互不影响
字符串类型
//示例1
let a = 'string1';
let b = a;
a = 'string2';
console.log(a,b) //输出 string2 string1
//示例2
let a = 'string1';
let b = a;
b = 'string2';
console.log(a,b) //输出 string1 string2
总结: 字符串类型的更改相互不影响
null类型
//示例1
let a = null;
let b = a;
a = 1;
console.log(a,b) //输出 1 null
//示例2
let a = null;
let b = a;
b = 1;
console.log(a,b) //输出 null 1
总结: null类型的更改相互不影响
Boolean类型
let a = false;
let b = a;
a = true;
console.log(a,b) //输出 true false
//示例2
let a = false;
let b = a;
b = true;
console.log(a,b) //输出 false true
总结: Boolean类型的更改相互不影响
undefined类型
let a = undefined;
let b = a;
a = 1;
console.log(a,b) //输出 1 undefined
//示例2
let a = undefined;
let b = a;
b = 1;
console.log(a,b) //输出 undefined 1
总结: undefined类型的更改相互不影响
栈个人理解总结
通过上面代码示例发现数值(Number)
、字符串(String)
、null(Null)
、undefined
、Boolean
就是会开辟一个栈空间,每个都是一个独立的空间,相互更改是不受影响的
堆
是堆内存的简称,堆是动态分配内存,内存大小不固定,也不会自动释放,堆数据结构是一种无序的树状结构,指针存放在
栈
内存中
那些类型会进入这个堆
空间: Object
、Array
、Function
个人理解堆
就是在一个空间栈中存放,然后是引用类型的关系,就是堆
中的a
被更改了, 然后引用a
的都会被更改
关于堆的代码示例:
Object类型
//示例1
let a = {name: 1};
let b = a;
b.name = 2;
console.log(a,b) //输出:{name: 2} {name: 2}
//示例2
let a = {name: 1};
let b = a;
a.name = 2;
console.log(a,b) //输出:{name: 2} {name: 2}
//示例3
let a = {name: 1};
let b = a;
a = {name: 2};
a.name = 3;
console.log(a,b) //输出:{name: 3} {name: 1}
总结:(示例1、2)是用了一个堆内存的空间,当堆内存发生变化,引用该堆内存的变量都会发生变化, 当重新定义一个新的堆内存的话就跟之前引用的没关系了(示例3)
Array类型
//示例1
let a = [1,2,3,4];
let b = a;
a[0] = 'h';
console.log(a, b) //输出:["h", 2, 3, 4] (4) ["h", 2, 3, 4]
//示例2
let a = [1,2,3,4];
let b = a;
b[0] = 'h';
console.log(a, b) //输出:["h", 2, 3, 4] (4) ["h", 2, 3, 4]
总结:array跟object一样a = b的话就是公用了一个堆内存,当该堆内存发生变化,a、b都回发生变化
function 类型
let a = function() {
return 123
}
let b = a;
//个人理解就是 function 本来就是一个独立的函数 如果把函数当作一个堆内存的话 就函数更改了的话 对应得变量也会更改
//function的我不知道怎么举例..... 抱歉 如果您了解这块可以放在评论区 感谢
避免这种堆得引用类型(深拷贝)
深拷贝(一)
// 利用JSON.stringify()
//示例1
let a = {name: 1};
let b = JSON.parse(JSON.stringify(a));
a.name = 2;
console.log(a, b) // 输出:{name: 2} {name: 1}
//示例2
let a = {name: 1, fn(){}}
let b = JSON.parse(JSON.stringify(a))
a.name = 1;
console.log(a,b) //{name: 1, fn: ƒ} {name: 1}
总结:利用JSON.stringify()
可以实现深拷贝,但是函数会丢失
深拷贝(二)
使用数组得slice 针对数组深拷贝
slice() 方法返回一个从已有的数组中截取一部分元素片段组成的新数组(不改变原来的数组!) 用法:array.slice(start,end) start表示是起始元素的下标, end表示的是终止元素的下标
当slice()不带任何参数的时候,默认返回一个长度和原数组相同的新数组
代码示例:
//示例1
let a = [1,2,3,4,5];
let b = a.slice();
a[0] = 'h'
console.log(a, b) //输出 ["h", 2, 3, 4, 5] (5) [1, 2, 3, 4, 5]
总结:slice适用于数组实现深拷贝
深拷贝(三)
使用数组得concat 针对数组深拷贝
concat() 不改变原数组,返回一个新得数组
代码示例:
//示例1
let a = [1,2,3,4,5];
let b = [].concat(a);
a[0] = 'h'
console.log(a, b) //输出 ["h", 2, 3, 4, 5] (5) [1, 2, 3, 4, 5]
总结:concat适用于数组实现深拷贝
深拷贝(四)
使用对象的Object.assign()
实现深拷贝
代码示例:
//示例1:
let a = [1,2,3,4,5];
let b = Object.assign([], a);
a[0] = 'h'
console.log(a, b) //输出: ["h", 2, 3, 4, 5] (5) [1, 2, 3, 4, 5]
//示例2:
let a = {name: 1, fn(){}};
let b = Object.assign({}, a);
a.name = 2;
console.log(a, b) //输出:{name: 2, fn: ƒ} {name: 1, fn: ƒ}
总结:Object.assign()
可以对数组和对象是实现深克隆。缺点:当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝
深拷贝(五)
es6扩展运算符...
实现深克隆
代码示例:
//示例1:
let a = [1,2,3,4,5];
let b = [...a];
a[0] = 'h'
console.log(a, b) //输出: ["h", 2, 3, 4, 5] (5) [1, 2, 3, 4, 5]
//示例2:
let a = {name: 1, fn(){}};
let b = {...a};
a.name = 2;
console.log(a, b) //输出:{name: 2, fn: ƒ} {name: 1, fn: ƒ}
//示例3
let a = {name: 1, fn(){}, obj: {a: 1}};
let b = {...a};
a.obj.a = 2;
console.log(a, b)
/**输出:{
"name": 1,
"obj": {
"a": 2
},
fn(){}
}
{
"name": 1,
"obj": {
"a": 2
},
fn(){}
}
*/
总结:...扩展运算符
可以对数组和对象是实现深克隆。缺点:跟Object.assign
一样当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝
深拷贝(五)
实现一个递归函数
function cloneDeep(source) {
//判断它是数组 还是对象 定义一个新的数组或者对象
let target = Array.isArray(source) ? [] : {}
for (let key in source) {
if (source.hasOwnProperty(key)) {
if (source[key] && typeof source[key] === "object") {
target[key] = cloneDeep(source[key]);
} else {
target[key] = source[key];
}
}
}
return target
}
//示例1、
let a = [1,2,3,4,5];
let b = cloneDeep(a);
a[0] = 'h';
console.log(a, b); //["h", 2, 3, 4, 5] (5) [1, 2, 3, 4, 5]
//示例2、
let a = {name:1, fn(){}, obj: {a: 1}};
let b = cloneDeep(a);
a.obj.a = 2;
console.log(a, b)
/**输出
*
* {
* fn: ƒ fn(),
name: 1,
obj:{a: 2}
}
{
fn: ƒ fn(),
name: 1,
obj:{a: 1}
}
* /
查阅相关资料
- 1、 zhuanlan.zhihu.com/p/50206683
- 2、www.cnblogs.com/guchengnan/…
- 3、juejin.cn/post/684490…
- 4、www.cnblogs.com/penghuwan/p…
- 5、www.jianshu.com/p/f9f587812…
总结
我对堆
和栈
的理解就这些,有发现我又不对的地方及时指出啊😀
结束语
- 大家好 我是三原,多谢您的观看,我会更加努力(๑•̀ㅂ•́)و✧多多总结。
- 每个方法都是敲出来验证过通过的,有需要可以放心复制。
- 如果您给帮点个赞👍就更好了 谢谢您~~~~~
- 期待您的关注