if与立即执行函数(IIFE)里面的变量提升

今天遇到一道笔试题,题目是这样的

1
2
3
4
5
6
7
8
9
f = function() {return true;};
g = function() {return false;};
(function() {
if (g() && [] == ![]) {
f = function f() {return false;};
function g() {return true;}
}
})();
alert(f()); // true or false ?

直接粘贴到浏览器运行会报错
g is not a function

奇怪了,按理说,就算外部 g 被覆盖,function 的声明方式也应该是提升并立即赋值的,我决定重新梳理一下这方面的知识

二、实验

1
2
3
4
5
6
7
8
console.log(bar); // undefined
console.log(foo); // error: foo is not defined
if(true){
foo = 'foo';
function bar(){
return 'bar';
}
}

如果我们给 if 中的 foo 加上 var 关键字

1
2
3
4
5
6
7
8
console.log(bar); // undefined  IE11之前都会把bar赋值好
console.log(foo); // undefined
if(true){
var foo = 'foo';
function bar(){
return 'bar';
}
}

说明 IE11 之后(至多在 firefox55,chorme60 之后),if 里面的 var 和 function 的声明方式,都会存在变量提升,但是并不赋值

在立即执行函数里面呢

1
2
3
4
5
6
7
8
console.log(bar); //  error: bar is not defined
console.log(foo); // error: foo is not defined
(function(){
foo = 'foo';
function bar(){
return 'bar';
}
}())

无论是各个版本的 IE 还是 chrome,firefox 都报错,说明 立即执行函数是一个函数作用域

我们在回过头来看这道题

1
2
3
4
5
6
7
8
9
f = function() {return true;};
g = function() {return false;};
(function() {
if (g() && [] == ![]) {
f = function f() {return false;}; // 还是外部的 f
function g() {return true;} // 变量提升,但是不赋值,并且覆盖外部 g
}
})();
alert(f()); // IE11以前返回false