1. 程式人生 > >JS中的變數提升和函式提升

JS中的變數提升和函式提升

在js中有一部分比較難以理解,卻也是在筆試過程中很容易考的,那就是變數提升和函式提升的問題,這篇文章我會就變數提升和函式提升的問題拓展一下有關js函式的知識點,包括作用域的問題,後面還會有一些小練習來判斷自己是否真的搞懂了。

作用域

在js中作用域分為全域性作用域和函式作用域,這裡是針對用var宣告的變數是全域性的,還是隻是在函式中可以使用,在es6中新增了兩個宣告變數的方法,let和var一樣,都是宣告變數的,不過let是在塊級作用域下起作用,const是用來宣告常量的,不能進行二次賦值。這裡重點是變數提升,就先用var來講解。

全域性作用域

什麼是全域性作用域?

全域性作用域是指在當前的script標籤內定義的變數,所有的函式都可以使用,它在開啟時建立,關閉時銷燬。在全域性作用域中有一個全域性物件window,window是由瀏覽器建立的,它裡面的方法所有物件都可以使用。

  • 在全域性作用域下建立的變數會作為window進行儲存,建立的函式會作為window的方法

什麼是全域性作用域下的變數提升?

終於說到變數提升了,那麼什麼是全域性作用域下的變數提升呢?看一下下面的例子:

        console.log(a);//undefined
        var a = 10;
        console.log(a);//10

由於在js中程式碼執行的順序是從上而下,所以在第一次列印的時候,要找變數a,如果沒有變數提升的話應該會會報錯說a沒有定義,而這裡輸出的是undefined,說明a已經定義了,但是沒有賦值。那麼這就是變數提升起了作用了。需要注意的是

  • 變數提升只會提升宣告,而不會提升賦值,也就是說在執行第一個列印操作時,只是存在變數a,a卻沒有值;
  • 列印結果是undefined說明變數存在,只是沒有值,而如果是報錯說a is not defined的話,就是沒有變數a。

什麼是全域性作用域下的函式提升?

函式提升和變數提升是一樣的道理,都是將本來應該在後面執行的程式碼全部放在前面,只是變數提升是提升宣告;而函式提升是提升整個函式,也就是在程式碼還沒開始執行的時候函式就會被建立。

呼叫在定義函式之後
        console.log(a);//undegfined
        var a = 10;
        function fun(){
            console.log(a);
        }
        fun();//10   

&nbsp&nbsp&nbsp這裡函式呼叫是在定義函式之後,看不出來函式是否存在提升的情況,但這裡值得一提的是,如果函式沒有需要訪問的變數的時候,就會去上一層找,就是這個全域性的a,值是10,所以會列印10.

呼叫在定義函式之前
        console.log(a);//undefined
        fun();//undefined
        var a = 10;
        function fun(){
            console.log(a);
        }
           

這裡函式呼叫是在定義函式之前,並且是在a賦值之前。首先我們來判斷一下,如果沒有函式提升的話會怎樣,執行到fun這一行,就會發現fun沒有定義,然後會報錯fun is not a function;現在有了函式提升過後,執行到fun後,會去找a,而a只是定義了沒有賦值,就會列印一個undefined,和第一個列印一樣的結果。

函式作用域

什麼是函式作用域?

函式作用域,顧名思義,就是隻在函式中能夠使用的變數,函式作用域和全域性作用域之間的關係是函式作用域中的方法可以使用全域性的變數,而全域性方法不能使用函式中的便來變數,每個函式之間也是不能取到各自函式內部的值的。下面的圖幫助理解一下:

每個函式作用域是相互獨立的,在函式內部定義的變數是不能進行相互呼叫的。

什麼是函式作用域下的變數提升和函式提升?

函式作用域中也存在變數提升和函式提升,這個和全域性作用域下的情況是一模一樣的,就是把作用域想成是全域性的就可以了。

練習

        var a = 123;
        function fun(){
            alert(a);//123
        }
        fun();
        var a = 123;
        function fun(){
            alert(a);//456
            var a = 456;
        }
        fun();
        alert(a);//123
        var a = 123;
        function fun(){
            alert(a);//123
            a = 456;
        }
        fun();
        alert(a);//456(456是因為函式內部將全域性的變數a的值改變了)
        var a = 123;
        function fun(a){
            alert(a);//123
            a = 456;
        }
        fun(123);
        alert(a);//456
 var a = 123;
        function fun(a){
            alert(a);//undefined(undefined是因為fun在被呼叫的時候沒有傳遞實參)
            a = 456;
        }
        fun();
        alert(a);//456

總結

在面試的筆試題中很容易碰到這樣的題,有的可能還不只是考這個知識點,可能還會涉及到閉包之類的,或者更難以理解一點兒的this指向問題,但是不管怎樣,只要知道原理,怎麼考都沒關係,願大家在前端這段路上堅持走下去,加油!