当开机时发生了什么?
当电脑开机时,会接通电源,电源直接联通电脑中的固件。固件就是内嵌在电脑中的存储设备,里面包含着开机程序。这时候会启动这个电脑系统,然后操作系统会在内存中启动。
操作系统启动后发生了什么?
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。