天天看點

變量提升與作用域——擴充題(面試題)練習

變量提升(聲)

  • 在JS代碼執行之前,浏覽器要先過一遍代碼,把其中 帶 var 和 帶 function 關鍵字内容提前聲明 ;
  • 帶 var 是隻聲明(給個預設值 undefined) 不定義
  • 帶 function 是聲明加定義
  • 因為 用function 關鍵字聲明的函數 ;在變量提升階段已經附好值了,是以 我們可以在JS檔案中的任意位置調用這個函數
  • 變量提升 隻會提升 = 号 左邊的部分; 不會提升右邊的部分
  • var 一個變量, 相當于 給 window添加一個屬性
  • 帶var 會進行變量提升 ,不帶var 的沒有變量提升
  • 變量提升 是不看條件成立不成立的; 這個是針對var 來說的
  • 針對 function 來說 ,在條件語句中的function聲明;标準浏覽器下是隻聲明,不定義的,在 IE低版本 是既聲明 也 定義的
* var a = 12;
    * let a = 12; // 不能重複聲明 能重複定義
    * let 沒有變量提升的;
    *
    * const a = 12;聲明常量用的 不能重複聲明  也不能重複定義
    * const  沒有變量提升
           
// console.log(a,b);
    // let c = 13;
    var c;//聲明
    c = 14;//定義
    var a = 12;
    var a = 13;
    var b = 13;

    //let
    let e = 13;
    e=23;
    // console.log(e);


    // console.log(a,b);
    // function sum() {
    //     console.log(1)
    // }
    // sum2();
    // var sum2 = function sum3() {
    //     console.log(2)
    // };
    // sum2();
    d = 2;
    // console.log(d);

    const aa = 14;
    // aa = 13;
    // console.log(f,g);
    console.log(sum2,sum3);
    if(1 > 2){
        var f = 12;
        function sum2() {
            console.log(12)
        }
    }else {
        var g = 14;
        function sum3() {
            console.log(13);
        }
    }
    console.log(sum2,sum3);
    // console.log(f,g);
           

作用域

  • 堆記憶體:存儲的對象鍵值對和函數的函數體
  • 棧記憶體:存儲基本資料類型 提供代碼運作的環境
  • 作用域: 屬于棧記憶體

    代碼執行都會有一個運作環境;我們把這個運作環境成為作用域;

  • 私有作用域 ----》函數執行會形成一個私有作用域;提供函數執行的環境
  • 全局作用域 ----》 頁面一打開就會形成一個全局作用域;這個作用域是提供整個JS執行環境的
  • 私有變量 ----》 在私有作用域下聲明的變量叫做私有變量 (通過 var聲明; 形參)
  • 全局變量 ----》 在全局作用域下聲明的變量叫做全局變量(var ; a = 12)
  • 作用域鍊 每一個私有作用域都會有他的上級作用域,他的上級作用跟他在哪定義的有關系

上級作用域

函數執行就會形成一個私有的作用域;那這個私有作用域的上級作用域 是誰?

跟這個函數在哪個作用域定義 有關系;在哪個作用域定義的,那麼他的上級作用域就是誰

函數執行的一個過程

函數執行, 先開辟一個私有作用域

然後再進行變量提升 (var function 提前聲明, 先形參指派, 再變量提升)

代碼從上到下 依次執行

// var foo=1;
    // function bar(){
    //     // 不管條件是否成立  都要進行變量提升
    //     // 這時的 foo 屬于私有變量 給的預設值是 undefined
    //     if(!foo){
    //         var foo=10;
    //     }
    //     // if(var i =0){
    //     //
    //     // }
    //     console.log(foo);
    // }
    // bar();
           

函數的上級作用域 隻跟函數在哪個作用域定義的有關系

跟函數在那裡執行 沒有任何關系

var n=0;
    function b(){
        n++;
        alert(n);
    }
    function a(){
        var n=10;
        b();
    }
    //函數的上級作用域 隻跟函數在哪個作用域定義的有關系
    //跟函數在那裡執行 沒有任何關系
    b();
    a();
    alert(n);
           

擴充題

1.

var n =10;

function outer(){

var n =15;

function inner(){

function center(){

alert(n)

}

center()

}

inner();

}

outer();

結果輸出是15;

第一步:

頁面打開形成全局局作用域,全局作用域裡面有var n=10 和 outer函數進行變量提升,然後代碼自上而下執行n=10;outer函數執行形成一個私有作用域

變量提升與作用域——擴充題(面試題)練習

形成私有作用域後,私有作用域裡的var n和inner進行變量提升,給inner函數一個堆記憶體的位址,然後代碼執行,n=15,inner函數執行,依次類推;

變量提升與作用域——擴充題(面試題)練習
變量提升與作用域——擴充題(面試題)練習

直接到center函數執行,到裡面alert(n)執行,因為center函數裡面沒有n變量,沒有傳參,是以查找上一級作用域,他的上一級作用域跟他在哪定義有關系,也就是inner函數,inner裡面沒有n,一直查找上一級作用域到outer函數,裡面有n=15,停止向上查找作用域;

2.

var n =10;

function a(){

var n =10;

function b(){

n++;

alert(n)

}

b();

}

a();

alert(n)

解析: 答案 : 11;0

全局作用域生成,var n=0,和function進行變量提升,給a這個函數一個記憶體位址;,然後函數自上而下執行,a函數執行,形成私有作用域,然後裡面var a =10,進行變量提升,給b函數一個記憶體位址,然後b函數執行,,裡面沒有形參指派和變量提升,n++,b函數裡面沒有n變量,從上一級作用域查找,上一級作用域是a函數,裡面有var n=10;是以b函數執行,n++。alert(n)是11;然後a函數執行完畢,到最後面第二個alert(n),也就是最外面的這個執行,

調用全局作用域,n變量,等于0;

3.

var n =0;

function b(){

n++;

alert(n);

}

function a(){

var n=10;

b();

}

b();

a();

alert(n);

這個a函數執行裡面的b()函數執行,b裡面的n仍從b的上級作用域全局作用域查找n變量,并不是b函數在a函數裡面執行,a函數就是b函數的上級作用域

函數的上級作用域 隻跟函數在哪個作用域定義的有關系

跟函數在那裡執行 沒有任何關系

變量提升與作用域——擴充題(面試題)練習

4.

f = function(){return true};

g = function(){return false};

(function (){

console.log(g);

if(g()&&[]==![]){

f= function f(){return false};

function g(){return true};

}

})();

alert(f());

alert(g())

輸出一個undefined報錯,

全局沒有變量提升,然後代碼自上而下執行,到function自執行函數執行形成私有作用域,私有作用域形成,裡面g函數進行變量提升,隻聲明不定義,是以console.log(g)輸出一個undefined,然後if裡面判斷執行,g不是一個函數,報錯;