内存和JS

80 阅读6分钟

image.png

一切都运行在内存里

  • 开机 操作系统在C盘里(macOS的在根目录下多个目录里)

当你按下开机键,主板通电,开始读取固件

固件就是固定在主板上的储存设备,里面有开机程序

开机程序会将文件里的操作系统加载到内存中运行

  • 操作系统
  1. 首先加载操作系统内核(操作系统把最基础的功能都嵌入了内核里面,如上网、文件管理、显示等)

  2. 然后启动初始化进程,编号为1,每个进程都有编号。
    (//在任务管理器中右键选中PID,PID就是编号)

  3. 启动系统服务: 文件、安全、联网

  4. 等待用户登录: 输入密码登录/ssh登录

  5. 登录后,运行shell,用户就可以和操作系统对话了

  6. bash是一种shell,图形化界面可认为是一种shell PS:

  7. bash是一种shell,一个叫ba的人写的shell

  8. 操作系统的内核叫作kernel,提供的操作界面叫作shell,我们用shell和内核进行交互,比如:我们会命令它去新建一个文件,打开浏览器等。。

打开浏览器(chrome.exe)

  1. 你双击chrome图标,就会运行chrome.exe文件
  2. 开启chrome进程,作为主进程
  3. 主进程会开启一些辅助进程,如网络服务、GPU加速
  4. 你每新建一个网页,就有可能会开启一个子进程

浏览器的功能

发起请求、下载HTML、解析HTML、下载CSS、解析CSS 、渲染界面、下载JS、解析JS、执行JS等

PS:HTML提供节点,CSS提供节点样式,解析完HTML和CSS后,把他们合起来放到屏幕上,这个动作叫作渲染

功能模块:

用户界面、渲染引擎(解析完HTML和CSS并把他们合起来渲染的代码)、JS引擎、储存等

上面的功能模块一般各处于不同的线程比进程更小

image.png 如果进程是车间,那么线程就是车间里的流水线了

JS引擎

  • Chrome用的是V8引擎,C++编写
  • Safari用的是JavascriptCore
  • IE用的是chakra(JScript 9)
  • Node.js用的是V8引擎

主要功能

  • 编译: 把JS代码翻译为机器能执行的字节码或者机器码
  • 优化: 改写代码,使其更高效
  • 执行: 执行上面的字节码或机器码
  • 垃圾回收: 把JS用完的内存回收,方便之后再次使用

执行JS代码

准备工作: 提供API:window/document/setTimeout

上面这些东西都不是JS自身具备的功能(使浏览器提供给JS的功能)

我们将这些功能称为运行环境(runtime env),一旦把JS放进页面,就开始执行JS

JS代码在哪里运行?(在内存)

内存图

image.png

红色区域

作用:

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

Stack和Heap

红色区域分为Stack栈和Heap堆

  • Stack区特点: 每个数据顺序存放
  • Heap区特点: 每个数据随机存放

stack和heap举例

  • 代码:
var a=1
var b=a
var person = {name:'frank' , child:{name:'Jack'}}
var person2 = person

image.png 如果是对象的话,直接把对象的地址传给Stack

  • 规律: 数据分两种:对象和非对象

非对象都存在Stack,对象都存在Heap

数组是对象、函数是对象

数字、字符串、布尔这三个不是对象,其他都是

“ = ” :等号总是会把右边的东西复制到左边(不存在什么传值和传址)

对象被篡改了

代码:

var person = {name : 'frank'}
var person2 = person
person2.name = 'ryan'
console.log(person.name)         //'ryan'

JS开发者说要有window,就有了window(浏览器提供的)

还要有什么?

要有console

于是就有了console,并且挂到window上,可以用window.console查看

要有document

于是就有了document,并挂到window上,可以用window.document查看

要有对象

于是就有了Object,并且挂到window上

var person = {}是简洁写法

var person = new Object()是完整写法

var person = {}等价于var person = new Object()

一般更倾向于简洁写法

要有数组(一种特殊的对象)

于是就有了Array,并且挂到window上

与上面一样,同理,

var a = [1,2,3]等价于var a = new Array(1,2,3)

要有函数(一种特殊的对象)

于是就有了Function,并且挂到window上

同理,

function f() {}等价于var f = new Function

怎么什么都挂window上?

因为方便,挂在window上的东西可以在任何地方直接使用。

比如,在window上挂xxx

window.xxx = function() {}

然后直接输xxx就可以调用函数

把window用内存图画出来

image.png

更简单的画法

image.png

console保存了console.log或者console.clear的地址

俗称window.console指向/引用了这个对象,保存了它的地址

细节

  • 关于window

window变量window对象是两个东西

window变量是一个容器,存放window对象的地址

window对象是Heap里的一坨数据

不信的话,可以让var x = window,那么这个x就指向了window对象,window变量就可以去死了。。。 但是,这样容易弄晕新手

  • 同理 consoleconsole对象不是同一个东西

ObjectObject函数对象不是同一个东西

前者是内存地址,后者是一坨内存

JS三座大山

  1. this 2. 原型链 3. AJAX

原型链

图里的prototype是干什么用的?

打印出来看看console.dir(window.Object.prototype)

当然window.可以省略

代码

var obj = {}
obj.toString()

为什么不报错,为什么可以运行?

  • 因为:

obj有一个隐藏属性,隐藏属性储存了Object.prototype对象的地址

obj.toString()发现obj上没有toString,就去隐藏属性对应的对象里找。

于是就找到了Object.prototype.toString

image.png

代码

var obj2 = {}
obj2.toString()

obj2和obj有什么联系?

  • 相同点 都可以调用.toString()
  • 不同点 地址不同obj不等于obj2 可以拥有不同的属性

xxx.prototype储存了xxx对象的共同属性

这就是原型

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

每个对象都有一个隐藏属性

这个隐藏属性指向原型

这个隐藏属性叫作__proto__

先关心小写字母的隐藏属性(obj...),不关心大写字母的隐藏属性(Object)

prototype和__proto__的区别是什么?

都存着原型的地址,只不过prototype挂在函数上。

__proto__挂在每个新生成的对象上。

  • 代码
var arr = [1,2,3]
arr.join('-')

为什么不报错?为什么可以运行?

  • 因为: arr有一个隐藏属性,隐藏属性储存了Array.prototype对象的地址

arr.join()发现arr上没有join,就去隐藏属性对应的对象里面找。

于是就找到了Array.prototype.join

image.png

Object和objec的区别是什么?

Object是一个全局函数,可以用来生成对象,var obj = new Object() 可以简写成var obj = {};

而object什么也不是,除非我声明一个var object

Object.prototype/Array.prototype/Function.prototype保存了一个对象的地址,这个对象包含了所有对象/数组/函数的共有属性,叫作对象/数组/函数原型

每个对象都有一个隐藏属性,用来保存其原型的地址,这个隐藏属性的名字叫作__proto__