理解 | 堆内存栈内存释放、null和{}、undefined的区别

Pink
文 / 景朝霞
来源公号 / 朝霞的光影笔记
ID / zhaoxiajingjing
图 / 自己画
❥❥❥❥点个赞,让我知道你来过~❥❥❥❥

【前情提要】

  1. 题目 | let和var的区别(一、二)
  2. 图解 | let和var的区别(一、二)
  3. 题目 | 带VAR和不带VAR的区别
  4. 图解 | 带VAR和不带VAR的区别
  5. 总结 | LET和VAR区别(三、四)
  6. 图解 | 作用域和作用域链
  7. 练习题 | 作用域和作用域链
  8. 图解 | 理解闭包
  9. 案例 | 闭包作用:保护和保存
  10. 图解 | 判断条件中的变量提升、私有变量、全局变量、arguments
  11. 理解 | 堆内存栈内存释放、null和{}、undefined的区别

【iview】

  1. iview低版本实现表格拖拽,滚动条列宽计算问题
  2. 案例 | iview中Table:拖拽适配列、自定义固定列、合并列
  3. 读源码 | 跟着大佬们学编程思想
  4. 上 | iview的Table组件合并列demo
  5. 下 | iview的Table组件合并列,升级代码

0 / 举个例子

var a = 10;
var obj = {
    id:'zhaoxiajingjing',
    name:'公号:朝霞的光影笔记'
};
function func(a) {
    console.log(a);
}
func(1);

公号ID:zhaoxiajingjing
△图13.1:代码的图解

内存分为:栈内存(stack),堆内存(heap);以谷歌的webkit为例,要清楚我们自己在打开浏览器时产生的堆栈内存:

(1)在浏览器中打开页面,浏览器引擎会渲染相关的代码(包括JS代码),把代码自上而下执行

(2)浏览器想要执行代码,会提供一个供代码执行的环境:Execution Context Stack(执行环境栈ECStack)栈内存

(3)最开始执行的是全局代码,所以会形成一个Execution Context(Global)全局执行上下文(EC(G)),在栈内存中执行全局代码

(4)在全局的执行上下文中有一个Variable Object (Global) 全局变量对象(VO(G)是有浏览器底层语言写的),可以把需要定义的变量和对应的值存储在这里

(5)var a =10;

① 创建一个值10(基本数据类型直接存储在栈内存中)

② 创建一个变量a(把其直接存储在VO(G)中)

③ 让创建的变量a和值10关联在一起(赋值操作)

(6)let obj = {id:'zhaoxiajingjing', name:'公号:朝霞的光影笔记'};

① 创建值:

1)开辟一个堆内存(heap),每一个堆内存都有一个16进制的地址

2)把对象中的键值对分别存储在堆内存中

3)把堆内存的地址存放在栈内存中,供变量的引用

②创建一个变量

③让变量和之前创建的堆内存地址进行关联

(7)function func(a){....}

①创建值:

1)开辟一个堆内存(heap),每一个堆内存都有一个16进制的地址

2)把函数体中的代码以字符串的格式存入到堆内存中

3)把堆内存地址存放在栈内存中,供变量的引用

②创建一个变量(函数名也是变量名)

③让变量和之前创建的堆内存地址进行关联

(8)func(1);函数执行

①创建一个全新执行上下文,浏览器开辟一块栈内存EC(func),并且压入执行环境栈中,才能执行

②初始化THIS

③初始化作用域链

④在当前执行上下文中有一个Activation Object 活动对象(AO(函数)是有浏览器底层语言写的),可以把:形参赋值、定义的变量和值存储在这里

⑤代码执行

函数执行就会形成栈内存(从内存中分配一块空间),如果内存都不销毁释放,很容易导致内存溢出(爆满,卡死了)。

数据类型:基本数据类型值和引用类型值

基本类型值:结构相对简单,直接把创建的值存储到栈内存即可

string、boolean、number、undefined、null、symbol

引用数据类型值:结构相对复杂(一个综合体,包含很多值),不能直接存储在栈内存中,需要单独开辟空间来存储,这个空间就是堆内存

(1)对象数据类型 object

普通对象{}、数组对象[]、正则对象/^$/、日期对象 new Date、数学函数对象 Math

(2)函数数据类型 function

1 / 栈内存释放

栈内存的两个作用:

1、提供代码执行的环境

2、存储基本类型值

打开浏览器形成的全局作用域是栈内存

函数执行形成的私有作用域是栈内存

基于ES6的let/const形成的块级作用域是栈内存

....

那么,栈内存释放:

1、全局栈内存:关闭浏览器

2、私有栈内存:

(1)一般情况下,函数执行完成,形成的私有栈内存就会被销毁掉(除无限递归、无限循环等)

(2)一旦栈内存中的某个东西(一般都是堆内存的地址)被私有作用域以外的事物占用了,则当前栈内存不能被立即释放销毁的(即:私有作用域中的私有变量等信息被保留下来了

2 / 堆内存释放

堆内存的作用只有一个:存储引用数据类型的值

创建一个引用数据类型的值,就会产生一个堆内存。

如果当前创建的堆内存不被其它东西占用了,浏览器会在空闲的时候,查找每一个内存的引用状况,不被占用的都会被回收释放掉。

let obj = {
    id:'zhaoxiajingjing'
};
let oop = obj;

此时,obj和oop都占用着对象的堆内存,想要释放堆内存,需要手动解除变量和值的关联。

null:空对象指针、空对象指针、空对象指针

obj = null;
oop = null;

3 / null、{}、undefined、''空字符串的区别

null和{}的区别

null:空对象指针{}空对象不一样、不一样、不一样

let obj = {}; // 开辟一块堆内存,里面内容是空的,有16进制的地址AAAFFF000
obj = null; // 把变量obj指向空对象指针,把AAAFFF000这个堆内存释放掉
typeof null === 'object' // true
typeof {} === 'object' // true

这是浏览器的bug,所有存在计算机中的值都是二进制编码存储的,浏览器中的typeof方法把前三位是000的都判断做对象。null的二进制前三位就是000,所以识别为对象。但它不是对象。

null的数据类型是:基本类型值;null是空对象指针、空对象指针、空对象指针。

null、undefined和''空字符串的区别
let a;
console.log(a); // 输出undefined
let b = '';
console.log(b); // 输出 '' 空字符串
let obj = {};
console.log(obj.c); // 输出undefined
console.log(obj); // 输出 {}
obj = null;
console.log(obj); // 输出 null

(1)创建了一个变量a,并未赋值,默认值是undefined

(3)创建了一个空字符串的值;创建了一个变量b;让其与空字符串关联。空字符串也是一个普通值。

(5)开辟一个堆内存(假设:16进制地址是AAAFFF000)里面的目前是空的,没有键值对;把堆内存地址存入栈内存中;创建了一个变量obj;让其与栈内存的堆内存地址关联。

(6)obj.c获取对象obj中的属性c,在obj中没有该属性,那么获取到的值是undefined

(8)释放对象obj的堆内存

4 / 预告

找THIS:

(1)

var a = 10;
function func(){
    // 这里的THIS是谁?
    console.log(this);
}
let obj = {
    id:'zhaoxiajingjing',
    name:'公号:朝霞的光影笔记',
    func:func
};

(2)

var a = 10;
function func(){
    // 这里的THIS是谁?
    console.log(this);
}
let obj = {
    id:'zhaoxiajingjing',
    name:'公号:朝霞的光影笔记',
    func:func
};
func();
window.func();
obj.func();

公号ID:zhaoxiajingjing

阅读 1.1k

朝霞的光影笔记
公号首发:朝霞的光影笔记 ID:zhaoxiajingjing →→→→ 多学一点知识,就少写一行代码

没有什么是20遍解决不了的,如果有~那就再写20遍

255 声望
12 粉丝
0 条评论
你知道吗?

没有什么是20遍解决不了的,如果有~那就再写20遍

255 声望
12 粉丝
宣传栏