在開發過程當中見到的IIFE,函數表達式都是匿名的,若是咱們把它寫成命名函數表達式,那全局做用域中豈不是多了一個變量,這樣又怎麼能保證不會污染全局變量呢?javascript
一般咱們在談論IIFE時,都是在談論它的用法,模塊化,閉包等等,卻少有說起它爲何能夠拿來作模塊化,爲何不會污染全局變量。前端
本文雖然是在說IIFE,可是並不會過多的介紹它的使用,或者其實踐意義(畢竟在標準中已經ES6的今天討論這個意義不是很大),更多的是討論這種寫法的自己在語法上會成立的緣由,爲何能夠在塊級做用域出現以前替代它,及其中涉及到的點。java
考慮下面代碼閉包
(function a(){
console.log('run a');
})();
console.log(a);
複製代碼
這段代碼運行在嚴格模式下,這裏說一下運行結果,a沒法打印,運行到這裏會報錯。模塊化
對運行結果存在疑惑?或許本文可以令你稍解疑惑。函數
IIFE能夠看作是兩部分構成,前半部分定義了一個函數表達式,後半部分的括號這是表示運行這個函數。拿一個具體的例子描述一下。組件化
(function a(){
console.log('run a');
})();
複製代碼
在上面的代碼中前半部分的圓括號定義了一個函數表達式,函數後面加上圓括號表示的語法是運行這個函數。固然IIFE的寫法不止這一種,還有其餘諸如,使用一個圓括號將函數表達式和後面的圓括號一塊兒括起來等各類寫法。ui
因爲標準中規定了function關鍵字開頭是一個函數聲明,因此要它變成函數表達式,咱們須要加點東西,好比在function 開頭加個 +,void,-等各類運算符,總之咱們的目的是不讓這一行以function開頭,這樣在語法解析式會認爲function(){}()是一個表達式去運行它,而不是當作函數聲明去解析它。看下面的例子:spa
console.log(+function s(){return 1}()) // 1
console.log(+function a(){}) // NaN
複製代碼
從上面的運行過能夠看出,IIFE執行時是將function(){}()總體做爲了一個表達式在運行的最終得出一個結果,固然在使用IIFE時咱們並不關心返回結果。code
IIFE不會污染全局變量的緣由,是函數表達式的特性。
當咱們使用函數表達式建立函數時,想在函數體內部使用當前函數,可使用命名函數表達式。這個函數名稱只會做爲函數體內部變量。換言之,使用表達式建立的命名函數,並不能和聲明函數同樣在聲明函數的做用域產生變量,而只會在這個命名函數內部產生這個變量,且該變量是隻讀的,不可被賦值。
var a = function c() {
c = 'test';
console.log(c); // ƒ c() {
// c = 'test';
// console.log(c);
// }
}
a();
console.log(c); // c is not defined
複製代碼
這裏咱們能夠理解,IIFE不會污染全局變量是利用了函數表式的特性,由此而衍生的種種寫法,只是爲了在語法上是的解釋器執行時可以識別這個表達式,而後執行它。當看到了這個本質的時候,對於它的種種寫法咱們就不須要去機械記憶了,咱們本身也能夠寫出不少。
究其根本,IIFE是充分理解了語言特性並結合時代需求的產物。這裏的特性更多的就是函數表達式的特性了,固然也有一部分語法特性的結合。需求固然就是所謂前端 「刀耕火種」 時代人們對組件化的探索。
放在篇文章下不合適,可是就是忽然想寫的話: 記得有一種論調說,前端的發展不過是把其餘語言多年前就已經實踐過的思想搬過來而已,所以以爲前端沒什麼技術含量,甚至產生優越感。可是我想說的是,思想並非某一語言,或者某一領域的全部物。不能由於年輕的事物,正在踐行別人實踐過的思想就認爲它是在抄襲照搬的,畢竟同一個思想的實踐在不一樣的需求下產生的火花是能夠徹底不一樣的。也藉此表達下前端仍是有不少獨特而有意思的東西的,這一細分領域的出現不過是時代需求的產物,你們都是爲需求服務的,因此沒有必要產生所謂優越感或者自卑感,畢竟更好的實現需求才是根本。