[ 深入理解JS | 青训营笔记 ]

73 阅读4分钟

JS基本概念

  1. 借鉴C语言的基本语法
  2. 借鉴Java语法的数据类型和内存管理
  3. 借鉴Scheme语言,将函数提升到“第一等公民”(first class)的地位
  4. 借鉴Self语言,使用基本原型(prototype)的继承机制

JS是单线程语言。

浏览器多进程、多线程

image.png

浏览器打开一个网页相当于新开了一个进程,进程有自己的多线程

  • Browser 进程(浏览器的主进程,只有一个)

    • 页面显示,与用户交互,比如前进、后退
    • 管理各个页面,创建和销毁其他进程
    • 网络资源管理,比如下载
  • 第三方插件进程

    • 每个类型的插件对应一个进程,进党使用插件时才创建
  • GPU 进程

    • 最多一个,用于3D 绘制
  • 浏览器渲染进程(浏览器内核)

    • 默认每个tab 页一个进程,互不影响
    • 页面渲染,JS脚本执行,事件处理等

浏览器的渲染进程是多线程的

  • GUI 渲染线程

    • 负责渲染页面,解析HTML,CSS,构建DOM 树,和RenderObject 树,布局和绘制等
    • 当页面需要重绘(Repaint)或者回流(Reflow)时,该线程就会执行
    • GUI 线程与JS 线程互斥,当JS 引擎执行时,GUI 线程会被挂起,GUI 更新会被保存在一个队列中,等JS 线程空闲时立即执行
  • JS 线程

    • 也称JS 内核,负责解析JS 脚本,运行代码
    • 一直等待任务队列中的任务,一个tab 页永远只有一个js 线程
    • 当JS 线程执行代码时,会将对应任务添加到事件线程中
  • 事件触发线程

    • 归属浏览器,而不是JS 线程,用来控制事件循环
    • 当事件被出发时,该线程会把事件添加到待处理队列的队尾,等待JS 引擎处理
    • 由于JS 是单线程,所以队列中事件都要排队等待JS 线程处理,当JS 引擎空闲时才会执行。
  • 定时器触发线程

    • 比如setInterval 和 setTimeout
    • 浏览器的计时器并不是由JS 线程提供的,在计时完毕后,添加到事件队列中,待JS 引擎空闲后执行,所以JS 计时器不准
    • setTimeout 中低于4ms 的时间间隔算为4ms
  • 异步http 请求线程(网络线程)

    • 在XMLHttpRequest 在连接后是通过浏览器新开的一个线程请求
    • 检测到状态变更时,如果有回调函数,异步线程就产生状态变更事件,将这个回调放到事件队列中,再由JS 线程执行

JS特点

  • 单线程

JS只能在JS线程上运行,但是JS线程和GUI线程互斥,JS线程和GUI线程只能保持一静一动的状态。

  1. 由于JS 线程可以操作DOM,如果在修改这些元素属性同时渲染页面,那么渲染线程前后获得的元素数据就可能不一致了
  2. 为了防止渲染出现不可预期的结果,浏览器设置GUI 渲染线程与JS 线程为互斥关系,当JS 线程执行时,GUI 线程会被挂起
  3. GUI 更新会被保存在一个队列中,等到JS 引擎线程空闲时立即执行

image.png

  • 动态、弱类型

运行时才确定数据类型的语言,变量在使用之前无需声明类型

const name = 'haha';

与之相对的就是,静态、强类型语言

编译时变量的数据类型就需要确定的语言

Sring name = 'haha';

简单数据类型

string ,number,boolean,undefined,null

值类型变量的数据直接存放在变量(栈空间)中

引用类型(复杂数据类型)

通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等

引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中

const a = {
    name: '11';
}
const b = a;
b.name = '222';
console.log(a, b);

image.png

对于复杂类型,存放的是变量的地址,所以将a赋值给b的时候,也就是将a的地址给了b,所以最后改变b的时候,也就是改变了地址所指向的那个变量。

const str = '111';
let newStr = '222';
console.log(str, newStr);

image.png

我们可以看到str的值并没有像上面的name属性值一样发生改变,因为对于基础数据类型赋值的时候的是给的原始的值

const arr = [1, 2];
arr.push(3);

const str = 'strstrstr';
str.slice(0, 2);

console.log(arr, str);

image.png

在JS中,复杂的数据类型的原始值是可以被改变的,但是基础类型的原始值是不可以被改变的。

作用域

image.png

image.png