1. 程式人生 > 實用技巧 >var的變數提升和let的

var的變數提升和let的

//es3/es5 //變數提升:當棧記憶體(作用域)形成,JS程式碼自上而下執行之前,瀏覽器首先會把所有帶var和function關鍵字的進行提前的 //宣告或定義.這種預先處理機制稱之為變數提升。 //宣告(declare):vara或functionsum //定義(defined):a=12也就是賦值 //變數提升階段: //帶var的只宣告未定義
console.log(a)//undefined
    var a = 12;
    function b(arr){//變數提升階段function就完成了宣告和賦值,瀏覽器會在全域性作用域宣告一個b,然後再形成一個堆記憶體裡面
        //是函式體裡面的程式碼字串。這個堆記憶體會有一個16進位制的地址,而全局裡面宣告的那個b就會指向這個地址
//因為函式在變數提升階段就完成了宣告和賦值,所以在程式碼執行階段在遇到b這個函式就不會在重複宣告賦值,就會直接跳過 for(let i=0;i<arr.length;i++){ console.log(i) } } //跳過後就會執行下面這個函式呼叫,傳了一個數組進去。 //而執行一個函式也就是形成了一個私有棧記憶體。當私有的作用域形成後也不是立即程式碼執行,而是先進行變數提升(變數提升前,先形參賦值) b([1,2,3,4]) //在ES3和ES5語法規範中,只有全域性作用域和函式執行的私有作用域(棧記憶體),其他大括號不會形成棧記憶體
//帶var與不帶var //在全域性作用域下宣告一個變數,也相當於給window全域性物件設定了一個屬性,變數的值就是屬性值(私有作用域下宣告的私有變數 //和window沒有關係) //帶function的宣告和賦值都完成了 //變數提升至發生在當前作用域(例如:開始載入頁面的時候支隊全域性作用域下的進行提升,因為此時函式中儲存的都是字串) //在全域性作用域先宣告的函式或者變數是‘全域性變數’,同理,在私有作用域下宣告的變數是‘私有變數’[帶var和function才是宣告
console.log(i)//undefined
    console.log(window.i)//undefined
    console.log('i' in
window)//true 在變數提升階段,在全域性作用域中聲明瞭一個變數i,此時就已經把i當做屬性值賦值 //給了window了,只不過此時還沒有給i賦值,預設是undefined // in? :檢測某個屬性是否隸屬於這個物件 var i = 9//變數值修改window的值也跟著修改 console.log(i)//9 console.log(window.i)//9 window的一個屬性名為i i=13 console.log(window.i)//13 window.i=14 console.log(i)//14 重點:全域性變數和window的屬性存在‘對映機制’,就是有一個改變另一個也跟著改變
//不帶var不帶var的本質是window的屬性
    //console.log(j)//j is not defined   這裡的J是按照變數的來識別的
    //console.log(window.j)//undefined    這裡是按照window的屬性來識別的,因為物件沒有某一個屬性返回的就是undefined
    //console.log(window.j)//false 不存在這個屬性
    j=10// 這裡不帶var 就相當於給window加了一個屬性叫j,值是10
    console.log(j)//10
    console.log(window.a)//12

    // var q =10,
    //     s =11 //這樣寫s是帶var
    // var q = s =11 // 這樣寫不帶var  
    //在私有作用域中帶var和不帶var也有區別:帶var在私有作用域變數提升階段都宣告為私有變數和外界沒有任何關係
    //不帶var 不是私有變數,它會想它的上級作用域查詢,看它是否是上級的變數,不是繼續向上查詢,一直找到window為止
    //這種查詢機制叫‘作用域鏈’
    //console.log(n,m)//undefined undefined
    var n =13;
        m =13;
    function fn(){
        console.log(n,m)//變數提升階段先var了一個n所以是 undefined 但是m不帶var,向上級查詢所以m是13  ;
        var n = m = 14//此時都是14
        console.log(n,m)//14 14
    }
    fn()
    console.log(a,m)// 這裡的a是全域性的所以是13,b在函式裡被重新賦值所以是14
//在私有作用域中如果向上級查詢變數到window的時候發現window也沒有這個屬性時又是怎麼做的呢?
function f(){
        b = 13
        console.log('b' in window)//true  在作用域查詢的過程中,如果找到window也沒有這個變數,相當於給window設定了
        //了一個屬性b
        console.log(b)//13
    }
    f()
    console.log(b)//13
//只對等於號左邊進行變數提升
fnn()// fnn is not a function 
    sun()//2 
    var fnn = function (){//函式表示式宣告 因為是用var關鍵字宣告在變數提升階段只提升了等號左邊的fnn,
        //但是並沒有定義或賦值,所以在上面呼叫時報錯
        console.log(1)
    }
    fnn()
    function sun (){//普通方式宣告的函式在 變數提升階段就已經宣告和定義完畢 所以上面可以直接執行
        console.log(2)
    }
    sun()
//條件判斷下變數提升
console.log(z)
    if(1===2){//在當前作用域下,不管條件是否成功都要進行變數提升,
        //帶var的還是隻是宣告
        //帶function的在老版本瀏覽器渲染機制下,宣告+定義都處理,但是為了迎合es6中的塊級作用域,新版瀏覽器對於函式
        //(在條件判斷中的函式),不管條件是否成立,都是先宣告,沒有賦值。
        var z = 10
    }
    console.log(z)

    if(1===1){
        console.log(fs)//函式本身:當條件成立,進入到判斷體中(ES6中它是以個塊級作用域)第一件事並不是變數提升,
        //先把fs宣告並定義,也就是判斷體中代買執行前,fs就已經賦值了
        function fs(){
            console.log('ok')
        }
    }
    console.log(fs)//函式本身
//ES6中let建立的變數不存在變數提升。不允許重複定義暫時性死區 //切斷了全域性變數和window屬性的對映機制
console.log(a)//a is not defined
    let a =12
    console.log(window.a)//undefined
    console/log(a)//12