面试常考:变量提升与暂时性死区,前端萌新疑惑解答

1,371 阅读3分钟

问题

console.log(web);// undefined
var web = "baidu.com";

还没声明web,就先去访问了,理论上会报错,但是这里输出undefined

这是因为js在解析代码时,会先把var声明的变量提升到函数作用域最顶部,这就是var的变量提升特性, 上方代码相当于

var web;
console.log(web);// undefined
web = "baidu.com";

再看一个例子,因为false,if代码不执行,为何下面还能访问到web?竟然不报错!

function ke() {
    if (false) { //false,代码不执行,为何下面还能访问到web?竟然不报错!
        var web = "baidu.com";
    }
    console.log(web); //undefined
}
ke();

输出也是undefined,不报错,原因也是变量提升(提升到函数作用域顶部),上面代码相当于

function ke() {
    var web;//这就是提升到函数级作用域最顶部
    if (false) { //false,代码不执行,但web已经定义在上方了
        web = "baidu.com";
    }
    console.log(web); //undefined
}
ke();

小结:变量提升是一件很不好的事情,意味着变量不先声明就能用了,后面程序员都尽量不使用var了,改用let和const

解决方法 暂时性死区TDZ

TDZ 又称暂时性死区,指变量在作用域内已经存在,但必须在let/const声明赋值成功后才可以使用,如果提前使用就要报错

TDZ可以让程序保持先声明后使用的习惯,让程序更稳定。

    console.log(web);//Cannot access 'web' before initialization
    let web = "baidu.com"

只有在let声明赋值成功后才可以使用变量,所以上方console会报错

再来看一个复杂点的案例

    hd = "houdunren";
    function run() {
        console.log(hd);//Cannot access 'hd' before initialization
        let hd = "hdcms";
    }
    run();

可能会有同学有疑惑,“run里的hd不能提前用,那不是还有run外面一个hd吗?怎么会报错?”

很简单,因为暂时性死区的性质: 变量在作用域内已经存在(画重点),hd说:"我存在啊,你不用去找外面的了",不过你不能在hd赋值完成前提前访问他,不然就报错了

说了那么多次赋值后才能访问了,可能就会有小机灵鬼来找茬了,如果let声明的hd没被赋值呢?

不要慌,看下方代码

    function run() {
        let hd;
        console.log(hd);//undefined
    }
    run();

说明什么?说明程序员就算是不给let声明的变量赋值,人家底层代码也是会先帮你赋上一个undefined,暂时性死区的总结仍然成立,你只有等到变量赋值成功后才能使用它

暂时性死区扩展

我们知道let 和 const 是声明的变量作用域为块级作用域,会产生暂时性死区TDZ

还有一种变量也会产生暂时性死区,它就是函数的形参

直接给出例子,

下面代码中,b形成暂时性死区,b赋值前,a不能提前访问b,报错

function hd(a = b, b = 3) {}
hd(); //Cannot access 'b' before initialization

因为a已经赋值,所以b可以使用a变量,下面代码访问正常

function hd(a = 2, b = a) {}
hd(); 

结束语: 本文所用代码示例摘自后盾人大佬的博客, 我在其基础上加了很多注释方便理解。后盾人大佬博客:doc.houdunren.com/