在前端面試中面試官基本都會問到什么是匿名函數、什么是閉包函數。
本文就先來說一下什么是匿名函數。
匿名函數顧名思義就是沒有名字的函數,通常我們所寫的函數都是這樣的:
1 function do(){ 2 // 執行代碼 3 }; 4 5 // 調用 6 do();
這種寫法是定義了一個名為do的函數,並通過函數名稱進行調用。
那如果沒有名字是什么樣子的啊?
1 function () { 2 // 執行代碼 3 };
這種寫法在編譯的時候會報錯:
Uncaught SyntaxError: Unexpected token (
這是為什么呢?原來時因為瀏覽器在進行語法分析的時候發現這個函數根本沒法執行。
那要為什么還要匿名函數呢?在編程語言中如果又個編碼方式那這種編碼方式肯定是能正常運行的,那該如何讓匿名函數跑起來呢?再看下面的例子:
var do = function () { // 執行代碼 } do();
這種函數大家肯定都知道,其實這種寫法就是將匿名函數復制為變量do,再通過變量名執行函數。
(function(){ // 執行代碼
console.log("打印成功"); })();
上面代碼是什么意思呢?
可以先把上面的代碼分幾個部分:
第一部分是括號里面的匿名函數,第二部分是加上括號的匿名函數,第三部分帶上最后面執行用的括號。
匿名函數在括號內部可以看成是將匿名函數當成是一個變量,再通過括號進行執行。
(function () { // 執行代碼 })(); // 相當於 var do = function() { // 執行代碼 }; do();
其實向上面這種匿名函數的寫法在很多地方都有用到,這種又叫自執行函數,像JQuery 等一些工具包都會用這種寫法,自執行函數有哪些優點呢?
1 // 定義一個全局變量a 2 var a = 1; 3 4 (function() { 5 // 在自執行函數中也創建一個變量a 6 var a = 2; 7 console.log(a); // 2 8 })(); 9 10 console.log(a); // 1
可以看到在自執行函數中打印出來的是2,而在自執行函數中打印出來的是1;
這是為什么?
因為在程序中有個名稱叫做作用域,全局環境的作用域叫做全局作用域,函數中的作用域叫做函數作用域,而作用域是分層的,內部作用域中可以訪問外部作用域中的變量,而外部作用域中卻不可以訪問內部作用域中的變量。
在內部作用域中訪問變量會先在自己所在作用域中查找,如果找不到再在上一層作用域中進行查找,再找不到還會再往上查找,一直到找到全局作用域。這種一層一層的關系像鏈條一樣所以被叫做作用域鏈。
再看上面代碼:在自執行函數中console.log 函數訪問了a變量,首先在自己所在的作用域中查找,找到了a變量,故輸出了a的值2;全局環境中的console.log 函數也訪問了a變量,由於外部作用域不能訪問內部作用域,所以全局環境中訪問的a變量只能在全局函環境中進行查找,所以輸出了a的值1;
總結:自執行函數的優點是為了保證自執行函數中的變量不會受到其他環境的污染。