上一篇文章:JavaScript的坑(一)有興趣的可以看看哦!
var a = 1;
function foo() {
if (!a) {
var a = 2;
}
alert(a);
};
foo(); // 輸出2,不是1!
alert(a)在執行的時候,會去尋找變量a的位置,它從當前作用域開始向(或者說向外)一直查找到頂層作用域為止,若是找不到就報undefined。
因為在alert(a)的同級作用域里,我們再次聲明了本地變量a,所以它報2;所以我們可以把本地變量a的聲明向下(或者說向內)移動,這樣alert(a)就找不到它了。像下面那樣:
var a = 1;
function foo() {
if (!a) {
(function() { // 這是 IIFE,它會創建一個新的函數作用域
var a = 2; // 并且該作用域在 foo() 的內部,所以 alert 訪問不到
}()); // 不過這個作用域可以訪問上層作用域哦,這就叫:“閉包”
};
alert(a);
};
foo();//輸出1
記住:JavaScript 只有函數作用域!
function test() {
foo();
//函數聲明
function foo() {
alert("我是會出現的啦……");
}
}
test();//輸出我是會出現的啦……
function test() {
foo();
//函數表達式
var foo = function() {
alert("我不會出現的哦……");
}
}
test();//報錯:Uncaught TypeError: foo is not a function
在第一個例子里,函數 foo 是一個聲明,既然是聲明就會被提升。函數聲明會連通命名和函數體一起被提升至作用域頂部。
在第二個例子里,被提升的僅僅是變量名foo,至于它的定義依然停留在原處。因此在執行foo()之前,作用域只知道foo的命名,不知道它到底是什么,所以執行會報錯(通常會是:undefined is not a function)。這叫做函數表達式(Function Expression)。
函數表達式只有命名會被提升,定義的函數體則不會。
函數聲明會在js解析器解析時候率先解析,保證其他代碼執行之前,函數可用。而函數表達式必須要等到代碼解析器解析到他所在代碼行,才會被解釋執行。