在变量提升中学习js

226 阅读2分钟

前提

众所周知,js的变量提升很烦人,常见的语言大部分都是函数声明提升,这很好理解,方便程序员,但是变量提升就常常会产生各种意想不到的输出结果。js之父Brendan Eichtwitter说过这样的话

var hoisting was thus unintended consequence of function hoisting, no block scope, JS as a 1995 rush job. ES6 'let' may help.

大概意思就是当年开发js这个需求太赶了,开发函数提升时,不小心带来了var变量提升

例子

1️⃣

var a = 1
function f() {
    if(a) {
        var a = 10
    }
    console.log(a)
}
f()
// 结果是undefined

咋看一下,会觉得结果是10,再看一下,会觉得结果是1, 但其实结果是undefinedimage.png

在执行f时,会把函数和变量的声明进行提升,所以对于f而言, var a存在变量提升并且初始化为undefined,这时候f里面的a就是undefined,而不是我们直觉的外部的a,所以不会命中判断逻辑,a也就不会被赋值, 所以输出的a就是undefined。

2️⃣

var a = 1
function f() {
    if(a) {
        let a = 10
    }
    console.log(a)
}
f()
// 结果是1

题目稍微改一下,var a改成let a, 这时候输出的结果就是1,这就是涉及到我们老生常谈的块作用域,let a 里的a只会在块里生效,一旦出了块,作用域就失效,所以下面输出的a其实是全局的a。 把if改成普通的块其实结果也是一样的,如下:

var a = 1
function f() {
    {
        let a = 10
    }
    console.log(a)
}
f()
// 结果是1

所以看到这里,那道经典的面试题你们应该会了吧, 把结果打在公屏上(bushi)image.png

function f() {
    var a = 0
    for(let a = 0; a < 5; a ++) {
    }
    console.log(a)
}
f()

3️⃣

题目继续改一下,

var a = 1
function f() {
    if(a) {
       function a(){}
    }
    console.log(a)
}
f()
// 结果是undefined

这时候可能就会有人抢答,说答案是function a() {},

image.png

我上面明明写了结果是undefined
很多资料不都好说function是创建,初始化,赋值一起的吗? 大部分情况确实是这样,但是这里产生了块作用域,MDN上面还特别标注了出来,

使用function
函数声明同样被限制在声明他的语句块内:

foo('outside');  // TypeError: foo is not a function  
{  
   function foo(location) {  
      console.log('foo is called ' + location);  
   }  
  foo('inside'); // 正常工作并且打印 'foo is called inside'
}

送分题

function f() {
    return ff()
    var ff = function() {return 1}
    function ff() {return 2}
}
console.log(f())

路过可以把答案打在评论区~