一切都运行在内存里
开机
- 操作系统在C盘里(macOS的在根目录下多个目录里)
- 当你按下开机键,主板通电,开始读取固件
- 固件就是固定在主板上的存储设备,里面有开机程序
- 开机程序会将文件里的操作系统加载到内存中运行
操作系统(以Linux为例)
- 首先加载操作系统内核
- 然后启动初始化进程,编号为1,每个进程都有编号
- 启动系统服务:文件、安全、联网
- 等待用户登录:输入密码登录/ssh登录
- 登录后,运行shell,用户就可以和操作系统对话了
- bash是一种shell,图形化界面可认为是一种shell
打开浏览器
chrome.exe
- 你双击Chrome图标,就会运行chrome.exe文件
- 开启Chrome进程,作为主进程
- 主进程会开启一些辅助进程,如网络服务、GPU加速
- 你每新建一个网页,就有可能会开启一个子进程
浏览器的功能
- 发起请求,下载HTML,解析HTML,下载CSS,解析CSs,渲染界面,下载JS,解析JS,执行JS(边解析边执行)等
- 功能模块:用户界面、渲染引擎、JS引擎(JS引擎单线程,渲染引擎跨线程通信,所以DOM操作慢)、存储等
- 上面功能模块一般各处于不同的线程(比进程更小)
- 如果进程是车间,那么线程就是车间里的流水线
JS引擎
JS引擎举例
- Chrome用的是v8引擎, C++编写
- 网景用的是SpiderMonkey,后被Firefox使用, C++
- Safari用的是JavaScriptCore
- IE用的是Chakra (JScript9),微软后来都用v8
- Edge用的是Chakra (JavaScript)
- Node.js用的是V8引擎
主要功能
- 编译:把JS代码翻译为机器能执行的字节码或机器码
- 优化:改写代码,使其更高效
- 执行:执行上面的字节码或者机器码
- 垃圾回收:把JS用完的内存回收,方便之后再次使用
执行JS代码
准备工作
- 提供API: window / document / setTimeout
- 没错,上面这些东西都不是JS自身具备的功能,我们将这些功能称为运行环境runtime env
- 一旦把JS放进页面,就开始执行JS
- 等一下,JS代码在哪里运行?
- 答:内存
- 哪里的内存?
- 答:查看一下内存图
内存图
红色区域
作用
- 红色专门用来存放数据,我们目前只研究该区域
- 红色区域并不存变量名,变量名在「不知什么区」
- 每种浏览器的分配规则并不一样
- 上图的区域并不完整,还没有画「调用栈」、「任务队列」等区域
Stack和Heap
- 红色区域分为Stack栈和Heap堆
- Stack区特点:每个数据顺序存放
- Heap区特点:每个数据随机存放
规律
- 数据分两种:非对象和对象
- 非对象都存在Stack
- 对象都存在Heap
- =号总是会把右边的东西复制到左边(不存在什么传值和传址)
- 对象的话,修改一个,另一个也会变,因为他们指向同一个地址,只适用于存在一层关系时,二层关系以上不适用
JS世界
浏览器提供了window
- window.console
- window.document
- window.Object,var person = {} 等价于 var person = new Object()
- window.Array,var a = [1,2,3] 等价于 var a = new Array(1,2,3)
- window.Function,function f(){} 等价于 var f = new Function()
怎么什么都挂在window上?因为方便,挂在window上的东西可以在任何地方直接用
把window用内存图画出来
window.dir(Object)
细节
关于window
- window变量和window对象是两个东西
- window变量是一个容器,存放window对象的地址
- window对象是Heap里的一堆数据
- 同理
- console和console对象不是同一个东西
- Object和Object函数对象不是同一个东西
- 前者是内存地址,后者是一堆内存
原型链
var obj = {}
obj.tostring()
为什么不报错?为什么可以运行?
obj有一个隐藏属性隐藏属性,存储了Object.prototype对象的地址
obj.toString()发现obj上没有toString
就去隐藏属性对应的对象里面找
于是就找到了Object.prototype.toString
如图所示:
由上图可知 :
- obj.toString === window.Object.prototype.toString
- a.push === window.Array.prototype.push
原型 prototype
xxx.prototype 存储了 xxx对象的共同属性, 这就是原型
原型的作用:让你无需重复声明共有属性,省代码,省内存
隐藏属性__proto__
每个对象都有一个隐藏属性__proto__,指向原型(原型也是一个对象)
prototype和__proto__区别
- 都存着原型的地址
- 只不过 prototype 挂在函数上(Object、Array等是函数)
- __proto__挂在每个新生成的对象上