We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
因为 JS 是运行在引擎中的,我们以 V8 为例,来理解下JS的运行过程。 首先来看下 v8 引擎的工作原理
v8 有许多子模块,但有4个重要模块:Parser(解析器)、Ignition(解释器)、TurboFan(编译器)、Orinoco(垃圾回收)
Parser(解析器): 负责将JavaScript源码转换为Abstract Syntax Tree (AST); 如果函数没有被调用,那么是不会被转换成AST的
Ignition(解释器): 负责将 AST 转换为 Bytecode(字节码),有一个监视器会监控函数的调用次数, 如果函数只调用一次,Ignition 会执行 Bytecode; 如果调用多次,JIT(Just-in-time 即时编译) 会把 Bytecode 送到 TurboFan 中编译成机器码,并把编译结果存储起来。
Node.js是基于V8引擎实现的,因此node命令提供了很多V8引擎的选项,使用node的 --print-bytecode 选项,可以打印出Ignition生成的Bytecode。
--print-bytecode
由于V8不会编译没有被调用的函数,因此需要在最后一行调用foo函数。
function foo(a) { var b = 2; function c() { } var d = function () { }; b = 3; } foo(1);
node --print-bytecode test.js
[generated bytecode for function: foo] Parameter count 2 Register count 2 Frame size 16 12 E> 0x75eaa296006 @ 0 : a5 StackCheck 28 S> 0x75eaa296007 @ 1 : 0c 02 LdaSmi [2] 0x75eaa296009 @ 3 : 26 fb Star r0 60 S> 0x75eaa29600b @ 5 : 81 00 00 02 CreateClosure [0], [0], #2 0x75eaa29600f @ 9 : 26 fa Star r1 80 S> 0x75eaa296011 @ 11 : 0c 03 LdaSmi [3] 0x75eaa296013 @ 13 : 26 fb Star r0 0x75eaa296015 @ 15 : 0d LdaUndefined 87 S> 0x75eaa296016 @ 16 : a9 Return Constant pool (size = 1) Handler Table (size = 0)
TurboFan(编译器): 将多次用到的函数,标记为热点函数,并编译成机器码,但是如果再后续执行过程中,类型发生变化,之前的机器码不再能正确处理,则会将机器码逆向转成字节码运算。
Orinoco(垃圾回收): 负责将程序不再需要的内存空间回收;
JavaScript 执行过程分为两个阶段,编译阶段、执行阶段。 编译阶段:词法分析 => 语法分析 执行阶段:执行上下文
JS 引擎(chrome 和 node 为 v8)会将代码当成字符串分解成词法单元(token)。所谓 token,指的是语法上不可能再分的、最小的单个字符或字符串。 例如:var answer = 6 * 7; 会被分解成
var answer = 6 * 7;
[ { "type": "Keyword", "value": "var" }, { "type": "Identifier", "value": "answer" }, { "type": "Punctuator", "value": "=" }, { "type": "Numeric", "value": "6" }, { "type": "Punctuator", "value": "*" }, { "type": "Numeric", "value": "7" }, { "type": "Punctuator", "value": ";" } ]
自动转换网站 https://esprima.org/demo/parse.html
将上一步生成的 token 数据,根据语法规则转为 AST。如果源码符合语法规则,这一步就会顺利完成。但如果源码存在语法错误,这一步就会终止,并抛出一个 “语法错误”。
{ "type": "Program", "body": [ { "type": "VariableDeclaration", "declarations": [ { "type": "VariableDeclarator", "id": { "type": "Identifier", "name": "answer" }, "init": { "type": "BinaryExpression", "operator": "*", "left": { "type": "Literal", "value": 6, "raw": "6" }, "right": { "type": "Literal", "value": 7, "raw": "7" } } } ], "kind": "var" } ], "sourceType": "script" }
执行上下文:指当前执行环境中的变量、函数声明,参数(arguments),作用域链,this等信息。分为全局执行上下文、函数执行上下文、eval 执行上下文,其区别在于全局执行上下文只有一个,函数执行上下文在每次调用函数时候会创建一个新的函数执行上下文。eval不常用,不做解释。
const ExecutionContextObj = { VO: window, // 变量对象 ScopeChain: {}, // 作用域链 this: window };
生成变量对象
建立作用域链
确定this的指向
变量对象是执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。 主要分为全局上下文的变量对象和函数上下文的变量对象。
举个例子:
function foo(a) { var b = 2; function c() {} var d = function() {}; b = 3; } foo(1);
在进入执行上下文后,这时候的 AO 是:
AO = { arguments: { 0: 1, length: 1 }, a: 1, b: undefined, c: reference to function c(){}, d: undefined }
在代码执行阶段,会顺序执行代码,根据代码,修改变量对象的值
还是上面的例子,当代码执行完后,这时候的 AO 是:
AO = { arguments: { 0: 1, length: 1 }, a: 1, b: 3, c: reference to function c(){}, d: reference to FunctionExpression "d" }
作用域链由当前执行环境的变量对象(未进入执行阶段前)与上层环境的一系列活动对象组成,它保证了当前执行环境对符合访问权限的变量和函数的有序访问。
var num = 30; function test() { var a = 10; function innerTest() { var b = 20; return a + b } innerTest() } test()
当执行到调用innerTest函数,进入innerTest函数环境。全局执行上下文和test函数执行上下文已进入执行阶段,innerTest函数执行上下文在预编译阶段创建变量对象,所以他们的活动对象和变量分别是AO(global),AO(test)和 VO(innerTest),而innerTest的作用域由当前执行环境的变量对象(未进入执行阶段前)与上层环境的一系列活动对象组成,如下:
innerTestEC = { // 变量对象 VO = { b: undefined}, // 作用域链 scopeChain = [VO(innerTest), AO(test), AO(global)], // this 指向 this: window }
总结一下作用域链的特点:
关于v8的详细课程,建议学习深入V8引擎
参考: https://finget.github.io/views/frontEnd/base/20210310.html#%E6%8F%90%E4%B8%80%E5%98%B4 https://www.cnblogs.com/bala/p/12205485.html https://zhuanlan.zhihu.com/p/72959191
The text was updated successfully, but these errors were encountered:
No branches or pull requests
v8 工作原理
因为 JS 是运行在引擎中的,我们以 V8 为例,来理解下JS的运行过程。
首先来看下 v8 引擎的工作原理
v8 有许多子模块,但有4个重要模块:Parser(解析器)、Ignition(解释器)、TurboFan(编译器)、Orinoco(垃圾回收)
Parser(解析器):
负责将JavaScript源码转换为Abstract Syntax Tree (AST);
如果函数没有被调用,那么是不会被转换成AST的
Ignition(解释器):
负责将 AST 转换为 Bytecode(字节码),有一个监视器会监控函数的调用次数,
如果函数只调用一次,Ignition 会执行 Bytecode;
如果调用多次,JIT(Just-in-time 即时编译) 会把 Bytecode 送到 TurboFan 中编译成机器码,并把编译结果存储起来。
Node.js是基于V8引擎实现的,因此node命令提供了很多V8引擎的选项,使用node的
--print-bytecode
选项,可以打印出Ignition生成的Bytecode。由于V8不会编译没有被调用的函数,因此需要在最后一行调用foo函数。
TurboFan(编译器):
将多次用到的函数,标记为热点函数,并编译成机器码,但是如果再后续执行过程中,类型发生变化,之前的机器码不再能正确处理,则会将机器码逆向转成字节码运算。
Orinoco(垃圾回收):
负责将程序不再需要的内存空间回收;
JavaScript 执行过程
JavaScript 执行过程分为两个阶段,编译阶段、执行阶段。
编译阶段:词法分析 => 语法分析
执行阶段:执行上下文
编译阶段
词法分析或分词(tokenize)
JS 引擎(chrome 和 node 为 v8)会将代码当成字符串分解成词法单元(token)。所谓 token,指的是语法上不可能再分的、最小的单个字符或字符串。
例如:
var answer = 6 * 7;
会被分解成自动转换网站 https://esprima.org/demo/parse.html
语法分析或解析(parse),生成 AST
将上一步生成的 token 数据,根据语法规则转为 AST。如果源码符合语法规则,这一步就会顺利完成。但如果源码存在语法错误,这一步就会终止,并抛出一个 “语法错误”。
执行阶段
执行上下文
执行上下文:指当前执行环境中的变量、函数声明,参数(arguments),作用域链,this等信息。分为全局执行上下文、函数执行上下文、eval 执行上下文,其区别在于全局执行上下文只有一个,函数执行上下文在每次调用函数时候会创建一个新的函数执行上下文。eval不常用,不做解释。
执行上下文的组成代码示例:
执行上下文的组成图例示例:
执行上下文生命周期
创建阶段
生成变量对象
建立作用域链
确定this的指向
执行阶段
变量对象
变量对象是执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。
主要分为全局上下文的变量对象和函数上下文的变量对象。
全局上下文的变量对象
函数上下文的变量对象
活动对象和变量对象其实是一个东西,只是变量对象是规范上的或者说是引擎实现上的,不可在 JavaScript 环境中访问,只有到当进入一个执行上下文中,这个执行上下文的变量对象才会被激活,所以才叫 activation object 呐,而只有被激活的变量对象,也就是活动对象上的各种属性才能被访问。
举个例子:
在进入执行上下文后,这时候的 AO 是:
代码执行
在代码执行阶段,会顺序执行代码,根据代码,修改变量对象的值
还是上面的例子,当代码执行完后,这时候的 AO 是:
建立作用域链
作用域链由当前执行环境的变量对象(未进入执行阶段前)与上层环境的一系列活动对象组成,它保证了当前执行环境对符合访问权限的变量和函数的有序访问。
举个例子:
当执行到调用innerTest函数,进入innerTest函数环境。全局执行上下文和test函数执行上下文已进入执行阶段,innerTest函数执行上下文在预编译阶段创建变量对象,所以他们的活动对象和变量分别是AO(global),AO(test)和 VO(innerTest),而innerTest的作用域由当前执行环境的变量对象(未进入执行阶段前)与上层环境的一系列活动对象组成,如下:
总结一下作用域链的特点:
关于v8的详细课程,建议学习深入V8引擎
参考:
https://finget.github.io/views/frontEnd/base/20210310.html#%E6%8F%90%E4%B8%80%E5%98%B4
https://www.cnblogs.com/bala/p/12205485.html
https://zhuanlan.zhihu.com/p/72959191
The text was updated successfully, but these errors were encountered: