1.一切都运行在内存里
是否好奇过,电脑按下开机键到屏幕亮起的这个过程中,发生了什么?我们知道,Windows操作系统在C盘中(macOS在根目录的多个文件夹中),当你按下开机键,主板通电,开始读取固件。固件是固定在主板上的存储设备,里面有开机程序,开机程序将文件里面的操作系统加载到内存中运行。
操作系统启动,首先加载系统内核,然后启动初始化进程,编号为1,每个进程都有编号。接下来启动系统服务:文件服务,网络服务,安全服务,等待用户登录,输入密码登录/SSH登录。登录后,运行Shell(Linux中的bash是一种Shell,图形化界面也可以认为是一种Shell),用户就可以和操作系统对话了。
打开Windows中的任务管理器,查看系统进程:
当我们双击Chorme图标,系统会运行chorme.exe文件,开启Chorme进程作为主进程。主进程会开启一些辅助进程,如网络服务、GPU加速等。
在谷歌浏览器中,设置》更多工具》任务管理器
下,可以看到浏览器启动的子进程:
2.浏览器的功能
- 发起请求,下载HTML,解析HTML,下载CSS,解析CSS,渲染页面,下载JS,解析JS,执行JS等。
- 功能模块:用户界面、渲染引擎、JS引擎、存储等,这些功能模块一般处于不同的线程中。
3.JS引擎
3.1 JS引擎举例
- Chorme用的是V8引擎,用C++编写
- 网景用的是SpiderMonkey,后被Firefox使用,也是用C++编写的
- Safari用的是JavaScriptCore
- IE用的是Chakra(JScript9)
- Edge用的是Chakra(JavaScript)
- Node.js用的是V8引擎
3.2 引擎的功能
- 编译:把JS代码翻译为机器能执行的字节码或机器码
- 优化:改写代码,使其更高效
- 执行:执行上面的字节码或机器码
- 垃圾回收:把JS用完的内存回收,方便以后再次使用
4 执行JS代码
4.1 准备工作
提供API:window/document/setTimeOut
,这些内容都不是JS自身具备的功能,都是浏览器提供给JS的功能,我们把这些功能称之为运行环境runtime env
。
那么当JS代码被浏览器加载后,JS代码在哪里执行?答案是内存,内存图示:
红色区域用于存放数据,但不存放变量名称。
4.2 Stack和Heap
Stack区数据顺序存放,Heap区数据随机存放。存储规律:非对象都存在Stack中,对象存在Heap中。 JS非对象的类型包括:数字,字符串,布尔值。
4.3 JS中的等号
与Java不同,JS中=
总是会把右边的东西复制到左边。举例:
var p1 = {name:"zhangsan"};
var p2 = p1;
p2.name = "lisi";
那么,p1.name
是什么?我是写Java的,第一次想当然的认为,当然是zhangsan
。结果:
4.4 浏览器提供的对象
- console
- document
- 对象
- 数组
var a = [1,2,3] 等价于 var a = new Array(1,2,3)
- 函数
function f(){} 等价于 var f = new Function()
上面列举出的对象,都是挂接在windows上的:
这样可以在任何地方直接使用。于此同时,还可以通过console.dir()
打印对象的内存结构。举例:
5.JS的原型链
我们知道,在Java中,如果你声明了一个Object对象,那么是自带toString(),equals,hashCode
方法的,那么在JS中呢?我们需要知道,JS中的对象都是有一个prototype
属性的,如下图:
所以,我们声明一个对象,也是自动带有这些propertype
中声明的属性。举例说明:
所以我们知道:JS中的所有对象都有一个隐藏属性,该隐藏属性存储了Object.propertype
对象的地址,a.toString()
发现a
上没有toString()
,就去隐藏属性对应的对象里面找,于是就找到了Object.propertype.toString()
如下代码:
var obj ={};
var array = [1,2,3]
内存图:
总结一下:XXX.prototype存储了XXX对象的共同属性,这就是原型。原型的存在,让我们无需声明对象之间重复的属性,可以省代码,省内存。于此同时,每个对象都有一个隐藏属性,指向原型对象。如下图:
__proto__
和peototype
都存储着原型的地址,只不过prototype
挂在函数上,__prototype__
挂在每个新生成的对象上。