函数提升与变量提升

以下内容不一定对,仅个人理解

众所周知,类似var a = 1;这种可分为两步,第一步编译为var a;提升至自身作用域(非块状作用域)最顶端,第二步执行a = 1;而函数也存在提升,如果函数与变量同时存在且同名时。函数优先提升,变量之后提升,由于变量提升时是重复声明,所以会被忽略掉。

var x = 1
function x(){}
console.log(x)    //1
//以上代码可看成如下
function x(){};  //函数提升,之后var x;变量提升,但属于重复声明,忽略
x = 1;  //执行x = 1

看完上面代码后我觉得我懂了,然鹅面试题跟我说,不,你不会。。。

var a = 0;
if (true) {
    a = 10;
    console.log(a, window.a);    //10 0

    function a() {}
    console.log(a, window.a);    //10 10
    a = 20;
    console.log(a, window.a);    //20 10
}
console.log(a);                    //10

上面的代码多了个块级作用域。情况就复杂了。
如果按照我之前的简单理解,函数提升至顶部。转换后代码如下:

function a(){}
a = 0;
if(true){
  a = 10;
  console.log(a, window.a);    //10 10

  console.log(a, window.a);    //10 10
  a = 20;
  console.log(a, window.a);    //20 20
}
console.log(a);                    //20
//可见以上代码运行结果跟原代码的并不一致

所以函数的提升应该不是简单的提升到顶部。特别是在存在块作用域的情况下
以下就纯属猜想了。
1、函数声明会提升至在其所在函数作用域顶部。但并未把函数体提升过去,仅创建一个函数名的变量标识,内容为undefined
2、函数声明会同时提升至块作用域顶部,创建类似let的块作用域变量(仅块作用域有效)
3、当运行至函数声明位置时,会将1步骤中提升至函数作用域顶部的变量重新赋值为当前值。
如果按以上三条规则,翻译原代码如下

var a; //函数提升至所在非块作用域(当前为全局)顶部
        //忽略第二次var a
a = 0; //第一次赋值(原var a = 0;拆分为var a和a=0)
if (true) {
    let a = function() {}; //函数提升至块作用域顶部(此处a与外部a不是同一个)
    a = 10; //块内赋值
    console.log(a, window.a);

     window.a = a;     //函数所在行执行后会映射至外部(最近的非块作用域)
     console.log(a, window.a);
     a = 20;
     console.log(a, window.a);
}
console.log(a);  

按以上规则顺利解决问题。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。