迷惑的知识点:
作用域
函数、闭包
面向对象
ES的新特性
其他知识
从图中可知 js、css文件并不是跟index.html文件一起下载下来的,而是需要时才会下载
浏览器内核来解析下载下来的文件
| 内存 | 使用 |
|---|---|
| Gecko | 早期被Netscape和Mozilla Firefox浏览器使用 |
| Trident | 微软开发,被IE4~IE11浏览器使用,但Edge转向使用Blink |
| Webkit | 苹果给予KHTML开发、开源的,用于Sfari,Google Chrome之前也在用 |
| Blink | Webkit的一个分支,Google开发,目前应用于Google Chrome、Edge、Opera等 |
| 。。。 | 。。。 |
浏览器内核常指浏览器的排版引擎
排版引擎(layout engine),也成为浏览器引擎(browser engine)、页面渲染引擎(rendering engine)或样板引擎
HTML Parser把HTML文件解析成DOM TreeDom进行操作从而修改Domt Tree,这执行Javascript代码就是js引擎CSS Parse解析成Style Rulescss规则Style Rules和Dom Tree结合(Attachment)到一起,生成渲染树(Render Tree)Painting)到界面上显示(Display)出来JavaScript代码通过JavaScript引擎来执行
| 引擎 | 使用 |
|---|---|
| SpiderMonkey | 第一款JavaScript引擎,有Brendan Eich开发 |
| Chakra | 微软开发,用于IE浏览器 |
| JavascriptCore | WebKit中的JavaScript引擎,由Apple公司开发 |
| V8 | Google开发的强大JavaScript引擎,也帮助Chrome从众多浏览器中脱颖而出 |
| 。。。 | 。。。 |
ECMAScript和WebAssembly,并在Windows7或更高版本,MacOS 10.12+和使用x64、IA-32、ARM或MIPS处理器的linux系统上运行
Parse解析Javascript源代码(包括词法分析和语法分析)成抽象语法树(AST)
AST可以通过V8引擎中的Ignition库转换成字节码(bytecode),不直接转换成机器码是为了根据运行环境做代码优化和环境适配等
V8引擎本身的源码非常复杂,大概有超过100w行C++代码,通过了解它的架构,我们可以知道他是如何对Javascript执行的
Parse模块会将Javascriptdiamagnetic转换成AST(抽象语法树),这是因为解释器并不直接认识JavaScript代码
Ignition是一个解释器,会将AST转换成ByteCode字节码
TurboFan优化所需要的信息(比如函数参数的类型信息,有了类型才能真实运算)Ignition会执行解释执行ByteCodeIgnition的V8官方文档https://v8.dev/blog/ignition-interpreterTurboFan是一个编译器,可以将字节码编译为CPU可以直接执行的机器码
Blink是Chrome内核,在解析到JavaScript时将JS代码通过流(Stream)的方式传到V8引擎Scanner(扫描器,做词法分析)Scanner将代码转换成许多Tokens,再通过Parse解析转化成AST
Parser就是直接将Tokens转成AST树结构PreParser称之为与解析
Outer()内部定义了Inner()函数,那么Inner()函数就会进行预解析在Parse阶段时,V8引擎会自动创建GlobalObject对象,比如Stirng、Date、Number、SetTimeout()、window...等都是GlobalObject的成员属性,所以在JS代码中可以字节调用这些对象
// 测试代码
var name = "why";
console.log(num1);
var num1 = 10;
var num2 = 20;
var result = num1 + num2;
foo(1)
function foo(num){
var m = 10;
var n = 20;
console.log('foo');
}
GlobalObject对象var GlobalObject = {
String : "类",
Date : "类型",
setTimeOut : "函数",
name : undefined,
num1 : undefined,
num2 : undefined,
result : undefined
foo : 0xa00
}
String、Date、setTimeOut是
GlobalObject自带的对象
name、num1、num2、result是解析出来的变量并添加到GlobalObject中
因为此时只是解析阶段,所以name、num1、num2、result都是undefined的
foo存储的函数地址
这些上下文中存在一个VO(variable object)(变量对象),其中VO分为GO和AO两种,全局上下文中VO = GO,函数执行上下文中VO = AO
代码从上下往下依次执行,从VO中取出目标对象并为其赋值
foo存储函数空间中存在一个父级作用域(parent scope),可以获得父级作用域中的数据,当foo作用域中的使用的数据在foo作用域中没找到就往父级作用域(parent scope)中查找,如果一直没有最终会找到全局作用域
var message = "Hello Global";
function foo(){
console.log(message);
}
function bar(){
message = "Hello Bar";
foo();
}
bar(); // 输出 Hello Global
GlobalObject对象foo的父级作用域(parent scope)就是GlobalObject
bar的父级作用域(parent scope)也是GlobalObject
赋值。。。
function foo(){
m = 100;
}
console.log(m);
function foo1(){
var a = b = 10;
/*
等价于
var a = 10;
b = 10;
*/
}
foo1();
console.log(a);
console.log(b);
foo函数来说,如果没有用var或者let定义变量,则m会被直接定义到全局变量(GO)中,所以对于console.log(m)会输出100而不是报错foo1函数来说,var a = b = 10;会被理解为var a = 10; b = 10;,根据1的解释,b会被定义到全局变量中,而a还在foo1的AO中,所以最后console.log(a)会报错,而console.log(b)会输出10每一个执行上下文会关联到一个环境变量(Variable Environment)中,在执行代码中变量和函数的声明会作为环境记录(Environment Record)添加到变量环境中
对于函数来说,参数也会被作为环境记录添加到变量环境中
所以对于上面的解释来说,将不再是VO(变量环境),而是环境记录(VariableEnvironment),也就是说不一定是O(object),只要是记录都行(map或者其他可以记录的类型)
不管什么语言,在代码执行的过程中都需要分配内存,不同的是某些语言需要手动管理内存,某些编程语言可以帮助管理内存
一般而言,内存管理存在如下的生命周期
JavaScript会在定义变量时为我们分配内存
因为内存是有限的,所以当内存不再需要的时候,我们需要对其进行释放,以便腾出更多的内存空间
再手动管理内存的语言中,我们需要通过一些方式来释放不再需要的内存,比如free函数:
1. 手动管理的方式会**影响编写逻辑的代码的效率**
2. 对开发者**要求较高**,不小心就会产生**内存泄漏**
JS引用使用标记清除算法,V8引擎为了更好的优化,它在算法的实现细节上也会结合一些其他的算法