内存图与JS世界

140 阅读4分钟

一切都运行在内存里

开机

  • 操作系统在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代码在哪里运行?
  • 答:内存
  • 哪里的内存?
  • 答:查看一下内存图

内存图

image.png

红色区域

作用

  • 红色专门用来存放数据,我们目前只研究该区域
  • 红色区域并不存变量名,变量名在「不知什么区」
  • 每种浏览器的分配规则并不一样
  • 上图的区域并不完整,还没有画「调用栈」、「任务队列」等区域

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用内存图画出来

image.png

image.png

window.dir(Object)

image.png

细节

关于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

如图所示:

image.png

由上图可知 :

  • obj.toString === window.Object.prototype.toString
  • a.push === window.Array.prototype.push

原型 prototype

xxx.prototype 存储了 xxx对象的共同属性, 这就是原型

原型的作用:让你无需重复声明共有属性,省代码,省内存

隐藏属性__proto__

每个对象都有一个隐藏属性__proto__,指向原型(原型也是一个对象)

prototype和__proto__区别

  • 都存着原型的地址
  • 只不过 prototype 挂在函数上(Object、Array等是函数)
  • __proto__挂在每个新生成的对象上