以前一直覺會認爲javascript代碼執行是由上到下一行行執行的。自從看了《你不知道的JS》後發現這個觀點並不徹底正確。先來給你們舉一個書本上的的例子:javascript
var a='hello world'; var a; console.log(a);
一開始我以爲輸出的是undefined。可是真正的結果是hello world。帶着疑問再看另一段代碼:java
console.log(a); var a='hello world';
借鑑與上面的例子會認爲會輸出一個hello world,或者是拋出一個沒有聲明的異常錯誤,然而發現這兩種想法也是錯誤。輸出的結果是‘undefined’。這書很是人性化的總結出告終論是:es6
引擎解釋javascript代碼的以前會對其進行編譯。在編譯過程當中會查找全部聲明,並用合適做用域將他們關聯起來。換句話說,在代碼執行以前,會對做用域鏈中全部變量和函數聲明先處理完先。因此,當遇到var a='hello world'中是 var a是先在編譯階段執行,而後在執行a='hello world'。因此,第一段代碼實質上是:函數
var a; a='hello world'; console.log(a);
因此輸出的就就是helloworld。總結一句話就是:只有聲明被提高,而賦值或其餘運算會留在原地。因此第二段代碼實際上就是:spa
var a; console.log(a); a='hello world';
介紹完這兩個經典例子是時候來看看一下這個例子了:code
var name = "world"; (function () { if (typeof name == 'undefined') { var name = 'yang'; console.log('Hello ' + name) } else { console.log('Hello ' + name) } })()
根據javascript的運行機制和javascript沒有塊做用域這個特色,能夠得出,變量name會聲明提高移至做用域 scope (全局域或者當前函數做用域) 頂部的。因此上述代碼就至關於:ip
var name = "world"; (function () { var name; if (typeof name == 'undefined') { var name = 'yang'; console.log('Hello ' + name) } else { console.log('Hello ' + name) } })()
所以,if判斷的時候typeof name == 'undefined'是true。因此會執行條件爲true裏面的代碼。輸出就是Hello yang。
那麼若是想實現上面的函數,咱們該如何實現?答案很是簡單那就建立塊做用域了。如何最簡單的建立塊做用域呢?那固然是採用es6的新特性let關鍵字。let關鍵字能夠將變量綁定到所在的任意區域中一般在{...}中。換句話說。let爲其聲明變量隱性劫持到所在區域中。下列例子中:let就綁定到if (typeof name == 'undefined') {...}中
。因此name不會被提高,因此判斷就爲假,因而就能夠輸出咱們期待已久的‘helloworld’。作用域
var name = "world"; (function () { if (typeof name == 'undefined') { let name = 'yang'; console.log('Hello ' + name) } else { console.log('Hello ' + name) } })()
注意點:let所在的塊級做用域,在聲明代碼被運行前,是不會像var那樣會被查找到,提早聲明,而是運行到了該代碼纔會被聲明執行。下面例子很好說明這個問題:it
(function (){ console.log(b); let b=2; })()
謝謝你們觀看,你們有什麼好見解能夠提出來討論討論。io