1.變量提高瀏覽器
在ES6以前,咱們聲明一個變量須要用到var關鍵字,用var來聲明的變量就存在變量提高的特性。函數
上述代碼粗略來說解,在上述代碼中存在全局做用域和函數做用域,在兩個做用域中都聲明瞭變量a。在fn函數執行console.log(a)的時候,先會在自身所處在的函數做用域中找到變量a,this
若是沒有找到,就會去全局做用域中找。spa
在fn函數做用域中咱們能夠看到a變量聲明並賦值了,可是它處於console.log(a)語句的下方,按照正常的邏輯,它不該該找到的是外層定義的a嗎?可是結果偏偏相反。對象
代碼執行流程:blog
咱們能夠根據位置來把代碼分爲全局代碼和函數(局部)代碼。在執行全局代碼前,首先將window添加爲全局執行上下文,以後對全局數據作預處理工做:作用域
(1)找到var關鍵聲明的變量,賦值爲undefined,且添加爲window的屬性。=>變量提高io
(2)將function聲明的變量賦值fun(),添加爲window屬性。=>函數提高console
(3)this =>賦值windowfunction
在預處理結束後,開始執行全局代碼。
函數代碼執行流程也和上述大同小異,這裏涉及到執行上下文,就不細講了,後續會補充。
因此咱們能夠這樣理解這行代碼
最後的結果天然就是undefined。這就是js存在的變量提高。
2.函數提高
函數提高和變量提高的原理同樣,區別就是在於,函數提高已經建立好了函數對象,而變量提高賦值爲undefined,能夠理解爲變量聲明提高。
3.拓展
(1)var fn = function(){}和function fn(){}的區別:前者爲變量提高,後者爲函數提高。
若是是用變量提高來聲明函數,若是在此前調用該函數,此時的函數對象並無建立,變量fn2賦值爲undefined,因此瀏覽器不能識別,把它當作函數來調用,因此最後報錯。
(2)在js中,函數是第一公民
被覆蓋的不是函數fn,而是var fn =3;
結果: