JS数据类型转换与内存模型
JS数据类型转换与内存模型
- JS数据类型转换
- 拓展知识:内存与外存
- 基础数据类型,对象,栈内存与堆内存
- 一道经典(SB)面试题的内存分析
- 垃圾回收与内存泄漏
- 深拷贝与浅拷贝的概念
JS数据类型转换
一张图表示,简单明了~

拓展:内存与外存
内存
内存分为RAM和ROM。RAM是随机存取存储器,用户可读可写,计算机断电后,存储在RAM的信息将被删除。RAM具体分为SRAM(Static RAM)和DRAM(Dynamic RAM)。我们 现在所说的内存一般指的都是DRAM,SRAM速度更快,但是容量相对于其他类型内存而言也会小一些,并且价格也较为昂贵。一般SRAM作为CPU和DRAM之间的缓存(cache)。ROM是只读存储器,ROM的内容是制造商写进去的,用户只能读,但不能写。ROM在切断电源后,数据也不会丢失。计算机会给当前执行的程序动态地分配内存空间,例如用户打开浏览器打开诸多网页,计算机会给浏览器分配内存,浏览器会给每一个页面分配内存,会给页面的HTML,CSS,JS分配内存。
外存
因为内存中的数据在断电之后会消失,所以为了数据的保存,就需要使用其他类型的存储器。这类存储器一般是磁盘,固态硬盘(ssd)等,也就是所谓的外存。
基础数据类型,对象,栈内存与堆内存
JS中的基础数据类型往往都保存在栈内存中,因为这些值都有固定的大小。
例如:var a = 1;
内存分配图大概是这个样子的:

var a = {'key':'value'};
内存分配图大概是这个样子的:

一道经典(SB)面试题的内存分析
var a = {n:1};
var b = a;
a.x = a = {n:2};
=============================
问:
console.log(a.x)= ?
console.log(b.x) =?
这道题涉及到了连续赋值的情况,在程序运行之后,先确定好了a.x 和 a的引用,然后再从右往左开始赋值 。本题的内存分析如下:
var a = {n:1};
var b = a;
代码执行到这里时,内存图模型如下:

a.x = a = {n:2};
时,JS首先会确定a在stack中的“地址”也就是指向对象的引用。
a.x = a = {n:2};
// 本例中a在stack中的地址为addr=31,在确定好这个信息后,代码会从右至左开始执行。
首先是a = {n:2}

a.x = a
,在内存模型中,此时左边的a在stack中对应的地址为addr31,而右边的a在stack中的地址已经变为了addr33。所以这个操作相当于在addr31所指向的对象中添加x属性,x的属性值为addr33指向的对象。


垃圾回收与内存泄漏
参考内容:JavaScript内存管理一文。
JS内存的声明周期
- 内存分配:在声明变量,对象时,系统会对内存进行自动分配
- 内存使用:在读写内存时,也就是我们在使用声明的变量,对象时,称为内存使用过程
- 内存回收:当一些数据被浏览器视作“垃圾”时,浏览器内部的GC回收机制会回收不再使用的内存。
垃圾回收算法
引用计数算法
引用计数算法定义“垃圾”的标准很简单,就是看一个对象是否有指向它的引用,如果没有就回收。但是引用计数算法却存在着许多问题,试想如果在堆内存中,有对象相互引用,即便是它们不再使用,但是GC不会进行回收,最后就会导致内存泄漏的问题,而IE6就是使用引用计数算法来进行垃圾回收的。 如代码:
function c() {
var o1 = {};
var o2 = {};
o1.a = o2;
o2.a = o1;
return "IE6'Bug"
}
c();
按理来讲方法在调用之后,对象o1,o2可以进行回收了,但是在堆内存中两者互相引用,是根据引用计数算法的定义,在堆内存的这两个对象还存在着引用的关系,所以这部分内存不会被回收,接下来就有可能带来内存泄漏的问题。什么是内存泄漏呢?内存泄漏(Memory Leak) 是指在程序中动态被分配的堆内存中,由于某种原因,导致程序未被释放或者说无法释放而造成了系统内存的浪费,进而导致程序运行速度减慢,甚至是系统崩溃。
标记清除算法
标记清除算法是现代浏览器主要使用,并在此之上加以改进并应用的算法,标记清除算法定义“垃圾”为从栈内存开始“无法达到”的对象。对于IE6出现的Bug,即便是堆内存中两个对象互相引用的情况,标记清除算法也可以进行回收。
深拷贝与浅拷贝的概念
如:
var a = 1;
var b = a;
这个过程就是深拷贝,对于基本类型来说,赋值的过程就是深拷贝。当我们尝试去改变b的值时,变量a的值不会发生变化,换句话说,一个变不会影响另一个这就是深拷贝。浅拷贝则恰恰相反,对于复杂类型而言:
var a = {name:'a'};
var b = a;
a和b指向同一个对象,当改变a.name或b.name时,另外的引用指向的对象(其实就是自己)会发生改变,所以我们可以这么理解:一个变会影响另一个变这就是深拷贝。对于复杂类型来说,也可以通过代码实现深拷贝,后续再见~
转载自:https://juejin.cn/post/6844903833345196045