JS世界与内存

592 阅读4分钟

当开机时发生了什么?

当电脑开机时,会接通电源,电源直接联通电脑中的固件。固件就是内嵌在电脑中的存储设备,里面包含着开机程序。这时候会启动这个电脑系统,然后操作系统会在内存中启动。

操作系统启动后发生了什么?

1、 操作系统的内核会加载

2、 启动初始化进程,第一个进程的pid编号为1,每一个进程都会有自己的编号

3、 所有进程加载完后,会等待用户登录

4、 用户登陆后,会打开一个shell。shell包括bashshell,视图化界面也可以看成一个shell。我们用cmd命令行 也是一个shell。

5、运行shell后,我们就可以跟操作系统交互

当打开浏览器时发生了什么?

打开浏览器后,首先会加载所有浏览器进程,这时候分浏览器主进程、辅助进程(网络、服务等),当用户打开一个新Table栏页面,也会打开一个进程。而进程里面则包括线程(js引擎、渲染引擎、用户界面、存储等)。js是单线程引擎,它与渲染引擎(css+html)的交互就叫做线程通信。

主要来说说js引擎吧

js引擎包含功能:

  • 可执行代码
  • 可优化代码
  • 垃圾回收
  • 编译代码

在执行代码中,我们详细说说这里面的内容。

首先需要一些前提准备工作:

浏览器为我们准备好了window对象、document对象、navigator对象、Settimeout等。这些都属于浏览器,不属于js。我们把这些称为runtime env(运行环境)。

当我们写好js代码后,浏览器会通过js引擎将其编译执行。

在哪里执行呢?

在内存中运行。没错,跟操作系统(os)一样,实际上os也是一种运行程序。

现在内存中有些什么呢?有os和各种进程,包括浏览器进程。我们用一张图来表示吧。

饥人谷提供

这时候可以看到在内存中有两个区,分别是Stack(栈)和Heap(堆)。Stack区的特点是顺序排列,Heap的特点是随机分布。这时候假设var 一个变量a。

如果a是字符串、数字等非对象,那么这个数据内容就存放在Stack区,【变量名称】单独放在【不知道什么区】。

如果a是对象,那么变量名词a依然放在【不知道什么区】,而对象数据则放在Heap区。但是在stack区会同时生成一个地址,用来连接变量名与Heap区间的关系。

为什么要这样放?

我们知道对象应该是可变的,包括数组都有push方法,可以自己修改自己。如果说都存放在Stack区,由于Stack区是顺序排列,计算机底层都是010101的数字。要修改对象的值,如果这个对象下面还有一些数据,那就要先让这些数据010101都往下退一个,才能插一个数据进去,这样会导致效率非常慢。 Heap区的内容是随机排列的,所以一般不会存在这样的问题。

var a=b会发生什么?

我们现在已经知道了变量名与数据之间的关系,(变量名存在不知道什么区。变量数据存在红色区(stack与heap))。变量名指向变量数据(可以理解为变量名是门牌号)。

如果b是一个非对象,那么就把b的在stack里面数据复制给a。

如果b是一个对象,就把b在stack区里面的数据复制给a。但是这个数据里保存的是一个地址,也就是所谓的引用。

所以可以比较出来,相同点都是把stack区的内容复制出去,但是区别是在stack里面的内容不同,一个是数据,一个是地址。 那么最终我们会发现对象被篡改了。

var b={};
var a =b;
b.name=1;
console.log(a.name);// 1

window

我们知道window这个对象是浏览器给的。那么这个window里面包含着什么呢? 打印下

好多内容,我们只需要先关注console、Object、Array。

饥人谷提供

更简单的画法

这个prototype保存的是共有的属性和方法。这个就叫原型 作用是可以让所有实例对象都可以使用,节省内存

等等 实例对象怎么和原型链接的呢?

答案:__proto__

只要新生成一个new 对象或数组等,都会产生这个默认,里面保存了与原型相连接的地址。一般__proto__挂在实例对象上

为什么Object跟Array也有呢

因为函数也是一个对象,Object跟Array 都是属于构造函数,自然也有这个属性,但是Array的是__proto__保存的地址是Object的Prototype,而Object的__proto__指向的是null。