var的變數提升和let的
阿新 • • 發佈:2020-12-24
//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就會指向這個地址//帶var與不帶var //在全域性作用域下宣告一個變數,也相當於給window全域性物件設定了一個屬性,變數的值就是屬性值(私有作用域下宣告的私有變數 //和window沒有關係) //帶function的宣告和賦值都完成了 //變數提升至發生在當前作用域(例如:開始載入頁面的時候支隊全域性作用域下的進行提升,因為此時函式中儲存的都是字串) //在全域性作用域先宣告的函式或者變數是‘全域性變數’,同理,在私有作用域下宣告的變數是‘私有變數’[帶var和function才是宣告//因為函式在變數提升階段就完成了宣告和賦值,所以在程式碼執行階段在遇到b這個函式就不會在重複宣告賦值,就會直接跳過 for(let i=0;i<arr.length;i++){ console.log(i) } } //跳過後就會執行下面這個函式呼叫,傳了一個數組進去。 //而執行一個函式也就是形成了一個私有棧記憶體。當私有的作用域形成後也不是立即程式碼執行,而是先進行變數提升(變數提升前,先形參賦值) b([1,2,3,4]) //在ES3和ES5語法規範中,只有全域性作用域和函式執行的私有作用域(棧記憶體),其他大括號不會形成棧記憶體
console.log(i)//undefined console.log(window.i)//undefined console.log('i' in//不帶var不帶var的本質是window的屬性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的屬性存在‘對映機制’,就是有一個改變另一個也跟著改變
//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