前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我理解的JavaScript预编译

我理解的JavaScript预编译

作者头像
wade
发布2020-04-23 16:26:36
4230
发布2020-04-23 16:26:36
举报
文章被收录于专栏:coding个人笔记coding个人笔记

JavaScript是一门单线程,解释型,弱类型的动态语言,解释一行执行一行。

JavaScript执行过程首先先语法分析,就是分析一遍代码有没有语法错误,解析期间不会执行代码。接着就开始预编译,预编译完了就开始一行一行执行代码。

预编译过程会创建两个对象,一个是全局的Global Object对象,简写GO,另一个是函数的Activation Object对象,简写AO。两个只是作用域不同,创建步骤是一样的。

预编译大概步骤:

创建AO、GO对象

找形参和变量声明,作为属性名,值为undefined

统一实参和形参

找函数声明,赋值函数体

说的抽象了,我们以一个函数为例:

代码语言:javascript
复制
function fn(a) {
  console.log(a);
  var a = 1;
  console.log(a);
  function a() {};
  console.log(a);
  var b = function () {};
  console.log(b);
  function c() {}
}
fn(3);

创建AO = {}

把形参和变量声明作为属性名和赋值undefined

代码语言:javascript
复制
AO  =  {
a: undefined,//参数a var a function a
b: undefined,//var b
c :undefined,//function c
}
统一形参和实参
AO  =  {
a: 3,
b: undefined,//var b
c :undefined,//function c
}

找函数声明,赋值函数体

代码语言:javascript
复制
AO  =  {
a: function a(){},
b: undefined,//var b
c: function c(){},
}

接着就是一行一行执行了:

代码语言:javascript
复制
function fn(a) {
  console.log(a);
  var a = 1;
  console.log(a);
  function a() {};
  console.log(a);
  var b = function () {};
  console.log(b);
  function c() {}
}
fn(3);
AO  =  {
  a: function a(){},
  b: undefined,
  c: function c(){},
}

当执行第一个打印的时候,打印出function,然后var a = 1的时候,声明已经声明过了,其实就a = 1,所以第二个打印是1,到了声明函数a的时候已经是声明过的,再打印也是1,至于b和c就不用多说了。最后结果就是f a(){}、1、1、f(){}。

其实可以记住几个点,函数声明是整体提升,变量声明只是声明提升。还有,如果一个变量没有声明,那么默认就是window的:

代码语言:javascript
复制
(function fn() {
  var a = b = 10;
}());
console.log(b);//10
console.log(a);//err

b没有直接var声明,那么就是全局window的,所以b能打印,a就会报错。

有个点要注意,JavaScript在预编译阶段, 会解释函数声明, 但却会忽略表式。比如一个自执行函数:

代码语言:javascript
复制
(function fn() {
}())

当执行到有()的时候,JavaScript会去对这个表达式求解得到返回值,返回的是一个函数且有(),所以直接执行了,其它的自执行函数原理都是这样的,都是通过表达式。函数转换为表达式的方法并不一定要靠分组操作符(),我们还可以用void操作符,!操作符+操作符等等。

代码语言:javascript
复制
+function () {}()
void(function () {alert(0)}())
console.log(function () {alert(0)}())

这些表达式都可以立即执行函数,就算+号得到的最终结果是NaN,但是在隐式转换之前却要先执行函数。

函数参数你可以看作在函数里面隐式的声明了一个变量a:

代码语言:javascript
复制
function fn(a) {
  var a;
  console.log(a);//3
}
fn(3)

而且函数参数里面在预编译过程中,会形成一个临时作用域,在预编译完了之后会消失:

代码语言:javascript
复制
function fn(a, b = function () {a = 5}) {
  console.log(a);//3
  b();
  console.log(a);//3
}
fn(3)

(a, b = function () {a = 5})这是一个临时的作用域,这里面的参数a就算改变了也影响不到原来的参数a。只有在参数作用域里面才有效果:

代码语言:javascript
复制
function fn(a, b = (function () {a = 5})()) {
  console.log(a);//5
  console.log(a);//5
}
fn(3)

(完)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 coding个人笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档