在當前作用域中,js**自上而下執行之前,瀏覽器首先會把所有的帶var/function關鍵字的進行提前宣告/定義。
注意宣告和定義的區別:
宣告(declare
):var num;
在當前作用域中吼一嗓子我有num這個名字了。
定義(define
):num = 12;
把宣告的名字賦值。
console.
log(a)
;//=>undefined
console.
log(fn)
;//=>輸出fn的函式體fn(
);//=>undefined, 1
var a =12;
functionfn(
)console.
log(a)
;//=>12
帶var關鍵字的只是提前宣告一下,帶function關鍵字的在變數提公升階段把宣告和定義都完成了。
注:var fn = function( )
和function fn( )
不一樣。
fn2()
;//=>fn2
function
fn2(
)// 因為var關鍵字宣告的函式,只宣告,不定義,所以不能再函式體之前執行。
console.
log(fn1)
;//=>undefined
fn1();
//=>typeerror: fn1 is not a function
varfn1
=function()
;
在全域性作用域中的區別:
【帶var】:var a;
在全域性作用域中宣告了乙個變數,同時也給全域性物件window設定了乙個屬性叫做a
。
【不帶var】:a = 12;
不帶var的情況在全域性作用域和私有作用域中都一樣。不帶var,則僅僅是給全域性物件設定了乙個新的屬性名。
注:在js中呼叫window的屬性和方法時,window可以省略。
舉個栗子:
//帶var
//變數提公升階段:在全域性作用域中var a;同時window.a = undefined
console.
log(a)
;//=>undefined
var a =12;
//**從上到下執行:a = 12; 全域性作用域中的a=12,同時window.a = 12
console.
log(a)
;//=>12
console.
log(window.a)
;//=>12
// 不帶var
// 沒有var就沒有變數提公升
console.
log(a)
;//referenceerror: a is not defined
//沒有變數提公升,所以這裡查詢的是全域性作用域中的變數a
a =12
;//這裡的賦值只是給全域性物件window中的a賦值,相當於window.a = 12;
console.
log(a)
;//=>12 這裡輸出的是window.a
console.
log(window.a)
;//=>12
在私有作用域中:// 帶var
functionfn(
)fn()
;console.
log(a)
;//referenceerror: a is not defined
//閉包機制:私有作用域保護裡面的私有變數不受外界干擾
// 不帶var
functionfn(
)fn()
;console.
log(a)
;//=>12
console.
log(window.a)
;//=>12
等號=
:賦值,等號左邊是變數,右邊是值(不管寫什麼都是值)。
item.classname = i%
2===0?
'c1'
:'c2'
;
匿名函式:函式表示式(把函式當做乙個值賦值給變數或者其他內容)。fn()
;//typeerror: fn is not a function
varfn
=function()
fn();
專案中,一般用函式表示式建立函式,因為這種方法只對函式左邊進行變數提公升,當前函式只有宣告沒有定義,因為只在賦值的**之後執行,這樣讓**邏輯更加嚴謹。varfn=
function
sum();
fn();
sum();
//referenceerror: sum is not defined
console.
log(num)
;//=>undefined
console.
log(fn)
;//=>undefinedif(
1===1)
}console.
log(num)
;//=>12
console.
log(fn)
;//=>[function: fn]
console.
log(num)
;//=>undefined
console.
log(fn)
;//=>undefinedif(
1!==1)
}console.
log(num)
;//=>undefined
console.
log(fn)
;//=>undefined
注意三點:
1)不管條件是否成立,判斷體**現的var/function都會進行變數提公升,但在最新版本的瀏覽器中,function宣告的變數只能提前宣告不能定義了(前提:函式定義在判斷體中)。
2)當**執行到條件判斷的地方:(新版本瀏覽器)
【條件不成立】:進入不到判斷體中,此時之前宣告的變數和函式依然是undefined。
【條件成立】:進入到判斷體中的第一件事,就是把之前變數提公升時沒有定義的函式首先定義了(進入到判斷體中函式就定義了:迎合es6中的塊級作用域)。
3)老版本的李蘭器不是這樣處理的。老版本中,不管條件是否成立,都要進行變數提公升(和新版本不一樣,新版本function只宣告,老版本function依然是宣告+定義)。
練習題:
// 變數提公升:沒有(沒有var就沒有變數提公升)f=
function()
;g=function()
;// **執行到這給window新增了兩個屬性:f和g。
~function()
functiong(
)}}(
);// 老版本瀏覽器下的結果
console.
log(f(
));//=>false
console.
log(g(
));//=>false
在變數提公升階段,若名字重複了,不會重新進行宣告,但會重新進行定義(後面賦的值會把前面賦的值給替換掉)。
舉個栗子:
// 變數提公升:fn = aaafff111 (=aaafff222) (=aaafff333) (=aaafff444)fn(
);//=>4
functionfn(
)fn()
;//=>4
functionfn(
)fn()
;//=>4
functionfn(
)fn()
;//=>4
js變數提公升
在了解變數提公升之前,應該先了解一下js到底是一種什麼型別的語言,他的執行機制又是怎樣的.console.log global undefined var global global console.log global global function fn fn 可以看出來 變數提公升只是將變數提...
js變數提公升
var a 100 functionf console.log a f undefined 200var a 100 functionf f console.log a 100如果你習慣了強型別語言的程式設計方式,那麼看到上述輸出結果你肯定會大吃一驚。我們來看一下c 的乙個例子 include us...
js變數提公升
function say say 在js中,瀏覽器在執行 前會有一次預編譯,這個過程會把函式宣告和變數宣告提公升到作用域的頂端,並賦值undefind,這個過程就叫提公升 並且在js中,函式是一等公民,優先順序是最高的,稍後會解釋 這就不難理解剛才那道題了,上面的 編譯後如下 function sa...