前提
众所周知,js的变量提升很烦人,常见的语言大部分都是函数声明提升,这很好理解,方便程序员,但是变量提升就常常会产生各种意想不到的输出结果。js之父Brendan Eich在twitter说过这样的话,
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, 但其实结果是undefined。
在执行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)。
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() {},
我上面明明写了结果是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())
路过可以把答案打在评论区~