js - 预编译


前言:js作用域的知识中可以了解到提升这一词,知道了变量和函数提升,但是做完一道题后我开始发现自己对提升这个还是不够了解。

代码一:
function test() {
  console.log(a);
  var a = 123;
  console.log(a);
}
test();

代码二:
function test(a) {
  console.log(a);
  var a = 123;
  console.log(a);
}
test(2);

代码三:
function test(a) {
  console.log(a);
  var a = 123;
  function a(){}
  console.log(a);
}
test(2);

这三段代码的结果:
我认为的: undefined, 123 \ undefined, 123 \ undefined, function a(){}
正确的: undefined, 123 \ 2, 123 \ unction a(){}, 123
如果结果跟你想的不一样的话,那就需要了解一下预编译了。

预编译发生时刻

js是单线程语言,在代码运行时会先进行语法分析,检查是否有语法错误,然后进行预编译,解释一行,执行一行。这就是js运行三个步骤:语法分析、预编译、解释执行。
js的声明和执行(赋值)是分开两步操作的,声明属于预编译环节。
js预编译分为全局预编译和函数预编译,全局预编译在js文件执行前一刻,函数预编译在函数执行前一刻。

预编译过程

全局预编译

全局预编译分为以下四步:

  1. 创建GO(全局/window)对象;
  2. 寻找var变量声明,并赋值为undefined;
  3. 寻找function函数声明,并赋值为函数体;
  4. 执行代码。
    在第2步中,针对未声明就赋值的全局变量,此时是不会有变量提升和被赋值undefined的,提前使用会报错。
console.log(test)
var test = 1;
console.log(test)
function test(a) {
  console.log(a);
  var a = 123;
  function a(){}
  console.log(a);
}
function test(b) {}
test(2);

这个过程就是:

第一步:创建全局对象
GO {
}
第二步:寻找var变量声明,并赋值undefined
GO {
test: undefined
}
第三步:寻找函数声明,并赋值为函数体
GO {
test: function test(a){...} => function test(b) {...} // 遇到同名覆盖
}
第四部:执行
// 第一个console: function test(b) {...}
// 第二个console:1 ,test 被赋值为1
// 遇到函数声明,跳过,test此时为1,test(2)执行失败

函数预编译

函数预编译和全局预编译大致相同,但是会增加形参的处理,分为以下五步:

  1. 创建AO对象;
  2. 寻找形参和var变量声明,并赋值为undefined;
  3. 将形参和实参统一,即将形参赋值(传入函数的值);
  4. 寻找function函数声明,并赋值为函数体;
  5. 执行代码。
function test(a) {
  console.log(a);
  var a = 123;
  console.log(a);
  console.log(b);
  function b(){}
}
test(2);

这个过程就是:

第一步:创建AO对象
AO{}
第二步:将变量和形参赋值为undefined
AO{
a:undefined
}
第三步:将形参和实参统一,赋值
AO{
a:2
}
第四步:将函数声明声明赋值为函数体
AO{
a:2,
b:function b(){}
}
第五步:执行
AO{
a:2,
b:function b(){}
}
// 第一个console: 2
// 第二个console:123,a被赋值为123
// 第三个console: function b(){}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值