JS 预编译代码实例分析
了解 JavaScript 引擎在执行代码过程中所做的一些行为是非常必要的,这有助于我们在遇到莫名其妙的调用时,能够大致定位问题所在。在我学习了预编译的相关知识,并基于该文章,引用其中的一段代码,结合“变量提升”、“函数提升”的小示例,对其进行详细的分析,算是留作一份笔记巩固记忆、加深理解。
代码
console.log(a)
fn1(1)
var a = 123
console.log(a)
var fn1 = () => {
console.log(a)
}
function fn1(a) {
console.log(a)
var a = 666
console.log(a)
function a() {}
console.log(a)
var b = function () {}
console.log(b)
function c() {}
}
fn1(1)
错误的推导会让你认为上述代码的打印如下:
如果你判断首行报错,那么需要了解变量提升
或者你这样认为
undefined
undefined
666
[Function: a]
[Function: b]
123
undefined
666
[Function: a]
[Function: b]
实际上,上方的代码打印如下:
undefined
[Function: a]
666
666
[Function: b]
123
123
详细分析
1. 创建全局对象 GO
在全局执行上下文中,创建全局对象 GO
。
2. 加载当前 JS 文件
加载并解析当前的 JavaScript 文件。
3. 脚本语法分析
进行语法分析,确保代码没有语法错误。
4. 当前 JS 文件预编译
4-1. 查找变量声明
GO = {
a: undefined
}
4-2. 查找函数声明(除了函数表达式)
GO = {
a: undefined,
fn1: function fn1(a) {}
}
5. 正常执行(执行到函数调用前)
console.log(a) // 打印 undefined
fn1(1) // 执行到这里了,小心,函数也有预编译,执行前一刻完成
6. 函数预编译
6-1. 创建活跃对象 AO
AO = {}
6-2. 查找变量和形参
AO = {
a: undefined,
b: undefined
}
6-3. 实参值和形参统一
AO = {
a: 1,
b: undefined
}
6-4. 查找函数(非函数表达式)
AO = {
a: function a() {},
b: undefined,
c: function c() {}
}
7. 正常执行函数(根据 AO)
console.log(a) // 打印 function a() {}
var a = 666 // a 改变,AO.a = 666
console.log(a) // 打印 666
function a() {} // 该声明已提升过,不会覆盖
console.log(a) // 打印 666
var b = function () {} // b 改变,AO.b = function () {}
console.log(b) // 打印 function () {}
function c() {} // 该声明已提升过,不会覆盖
8. 接着执行函数外代码,执行到下个函数调用前
fn1(1) // 已讲述,上续
var a = 123 // GO 对象中的 a 改变为 123(undefined > 123)
console.log(a) // 打印 123
var fn1 = () => { // fn1 改变,GO.fn1 = () => {...}
console.log(a)
}
function fn1(a) { // 该声明已提升过(函数提升),不会覆盖
...
}
fn1(1) // 执行到这里时,预编译
9. 函数预编译
9-1. 创建活跃对象 AO
AO = {}
9-2. 查找变量和形参
AO = {
a: undefined
}
9-3. 实参值和形参统一
AO = {
a: 1
}
9-4. 查找函数(非函数表达式)
AO = {
a: 1
}
10. 正常执行函数(根据 AO)
console.log(a) // a 不存在当前函数作用域,往上级查找,找到 GO.a,打印 123
总结
- 全局预编译:创建 GO 对象,查找变量声明和函数声明。
- 函数预编译:创建 AO 对象,查找变量和形参,实参值和形参统一,查找函数声明。
- 执行阶段:按照代码顺序执行,变量赋值和函数调用。
JS 预编译代码实例分析的更多相关文章
- js预编译
先来做三个测试 eg1: var a; a = 1; function a() {}; console.log(a); eg2: var a; function a() {}; console.log ...
- Handlebars.js 预编译(转)
Handlebars.js 官网上对预编译1是这样说的: 你需要安装 Node.js 你需要在全局环境中,通过 Npm 安装 handlebars 包 然后你就可以通过命令预编译你的 handleba ...
- 一个proc预编译代码时coredump的问题分析
最近有同事在搞编译环境迁移,碰上一个问题让我帮他看一下. 他建了一个新目录,然后把现在的代码拷过去,编译的时候发现有一个文件编译不了一执行就出现core,不知道啥情况. 我进到他的编译环境 ...
- js 预编译
js 运行代码的时候分为几个步骤:语法分析 ==>预编译 ==>解释执行 语法解析:通篇扫描代码,查看语法是否出错 解释执行:读一行 - 解释一行 - 执行一行 预编译执行的操作: // ...
- 关于js预编译以及js文件执行顺序的几个问题。
关于js的执行原理,除去html页面中直接添加的代码,js代码的放置可以分为两类. //情形a <script type="text/javascript" ...
- JS预编译详解
我们都知道javascript是解释型语言,执行的特点呢是编译一行,执行一行.按照这个思路有时候我们在运行代码时会有一些令人费解的现象出现.下面我们一起来执行下面三段代码. <script> ...
- js预编译和函数执行
javascript 执行过程 1.语法检测(有没有基本的语法错误,例如中文,关键字错误...)2.词法分析(预编译) (1)创建全局GO(global object)对象 (2)对var声明的变量进 ...
- js预编译的四部曲
众所周知javascript是解释性语言,主要特点为解释一行执行一行. 而在js运行时会进行三件事:1语法分析 2.预编译 3.解释执行 语法分析会在代码执行前对代码进行通篇检查,以排除一些低级错 ...
- JS预编译过程
GO和AO 变量的预编译 实例1 console.log(a); var a=1; console.log(a); 实际编译过程: 将a存入预编译对象中,赋值为undefined: 真正的赋值语句当程 ...
- js预编译环节 变量声明提升 函数声明整体提升
预编译四部曲 1.创建AO对象 2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined 3.将实参和形参统一 4.在函数体里面找函数声明,值赋予函数体 function fn(a) ...
随机推荐
- 坑人的opencv安装
我想捡起来C++,最近在看opencv,于是我想着一起吧. 但是我低估了这个小麻烦的魅力,曾经安装opencv c++版本就头秃,如今依然头秃.说明我没长进啊-- 折腾了两天,终于装上了. 其中最麻烦 ...
- SQL Server – Concurrency 并发控制
前言 以前写过相关的, 但这篇主要讲一下概念. 帮助理解 Entity Framework with MySQL 学习笔记一(乐观并发) Asp.net core 学习笔记 ( ef core tra ...
- 服务器文件打压缩包下载(java)
public void download(HttpServletRequest request, HttpServletResponse response){ try { String downloa ...
- 系统编程-进程-当文件操作遇上fork
我的关联博文: 系统编程-进程-fork深度理解.vfork简介 系统编程-进程-先后fork或open一个文件的区别 test1: lseek基本使用 #include <stdio.h& ...
- 6How To Use Messages With Flask - Flask Fridays #6 10:43
消息闪现 消息闪现 {% for message in get_flashed_messages() %} <div class="alert alert-success alert ...
- Laravel视图共享数据
Laravel视图共享数据 最近在用lavavel过程中想实现公共头部尾部需要的配置数据在所有的页面中都可以使用,便查看了官方文档,在此做一个总结: 一. 修改 ComposerServiceProv ...
- dotnet 使用自定义特性
namespace TETTD.Common { /// <summary> /// 导入excel特性 标记字段映射的列 /// </summary> [AttributeU ...
- C# 的显示转换 *.Parse(string) Convert.ToInt32(double value)
// 显式转换 (类型) /// (int)表示使用强制的显示转换,是一种类型转换,C#默认的整形是 int32 , /// 因此使用此方法转成int32 不遵循四舍五入,直截取整数部分 /// (i ...
- 40. diff 的新旧节点数组如何比较
根据唯一标识符key值,把新旧的节点比较,不同就更新到新节点,相同就复用就节点,然后生成新的 Vnode :
- 002 Typora 的使用(markdown 的使用)
博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https:// ...