前端基础系列(四) -- 内存

概述

电脑开机之后就把硬盘中的数据传输到内存中,例如操作系统,把硬盘中的操作系统读到内存中即是开机。内存特点是:存储数据快,一旦断电,数据就丢失了。与内存相对应的是外存,表示无论断电与否,数据都存在,外存的存储速度慢。

示例

Chrome 浏览器打开之后大约占用了 1G 的内存,分别分配给每个页面,每个页面大约占用 100M ,其中包括了:

1. HTML + CSS
2. JavaScript
3. 网络 HTTP
4. 其他

所以 JavaScript 最多占用约 100M 的内存。

内存分类

JS 将内存划分为两个大区,分别是代码区(存储代码)数据区(存储数据)

1
let  a = 1  // 变量 a 存储在代码区  数字 1 存储在数据区 二者以 JS 引擎关联

数据区

数据区分为 Stack(栈内存)Heap(堆内存)

  • Stack(栈内存)存储方式是以一行一行存储,类似栈,故而叫做栈内存

  • Heap(堆内存)存储方式是以堆存储

存储

  1. 数字是以 64 位浮点数进行存储
  2. 字符是以 16 位的进行存储。
  • 存储 var a = 1 时,a 在代码区,1 以64位浮点数存储在栈内存。

  • 存储 var b = 2 时,b 在代码区,2 以64位浮点数存储在栈内存。

注意:b = a 时,将 a 中的数据复制并覆盖到 b 的数据上。

  • 存储 var a = true 时,a 在代码区,true 转化为 1 ,之后以64位浮点数存储在栈内存。

  • 存储 var obj1 = {} 时,obj1 在代码区,在栈内存中会存有一个以64位浮点数的地址,引用的是堆内存中的一个地址,obj1 中的数据将存储在堆内存中的一个地址,如果在后面在 添加 obj1 的属性 ,继续放在堆内存中。

  • 存储 var obj2 = {} 时,obj2 在代码区,在栈内存中会存有一个以64位浮点数的地址,引用的是堆内存中的一个地址,obj2 中的数据将存储在堆内存中的一个地址。

注意:obj2 = obj1 时,和 b = a 做的事情完全相同,即将 obj1 中的数据地址复制并覆盖到 obj2 的数据地址上。

数据类型存储方法:

JavaScript 中有 7 种数据类型

  1. 简单数据类型(6种)直接存储在 Stack(栈内存)

  2. 复杂数据类型(Object)在 Stack(栈内存)中存储 Heap(堆内存)的地址

    所有的变量和对象的关系都是引用关系。

套路:

1
2
3
4
5
var a = { n: 1 };  
var b = a;
a.x = a = { n:2 }; //当浏览器运行这句话时,首先确定 a 的值,之后执行 { n:2 },之后执行 a = { n:2 },之后执行 a.x (此时的 a 是之前确定的 a )。
alert( a.x ); //undefined
alert( b.x ); //[object Object]

内存图

基本概念

垃圾回收

如果一个对象没有被引用,就是垃圾,将会被回收(释放内存)。

内存泄露

由于浏览器的 BUG ,使得应该被标记为垃圾的东西,没有被标记为垃圾,造成内存被永久占用,除非把浏览器关闭。
解决方法:在关闭页面之前把所有的事件设置为 null 。

浅拷贝&深拷贝

基本数据类型
1
2
3
4
var a = 1;
var b = a;
b = 2; // b 变不影响 a,即是深拷贝
alert( a ); // 1

对于基本类型,所有的赋值 “ = “ 都是深拷贝

所以在谈及深拷贝和浅拷贝时是不考虑基本类型的,因为基本类型的赋值都是深拷贝

复杂数据类型(Object)

浅拷贝:

1
2
3
4
var a = { name : 'a' };
var b = a;
b.name = 'b' ; // b 变致 a 变,即是浅拷贝
alert( a.name ); // 'b'

深拷贝:b 复制 a 的所有数据,但是地址不同,最终的结果就是 b 变是 b 自己的事情,与 a 无关,即 b 变不影响 a