深入理解變數宣告提升和函式宣告提升
變數宣告提升
1、變數定義
可以使用var定義變數,變數如果沒有賦值,那變數的初始值為undefined
。
2、變數作用域
變數作用域指變數起作用的範圍。變數分為全域性變數和區域性變數。全域性變數在全域性都擁有定義;而區域性變數只能在函式內有效。 在函式體內,同名的區域性變數或者引數的優先順序會高於全域性變數。也就是說,如果函式記憶體在和全域性變數同名的區域性變數或者引數,那麼全域性變數將會被區域性變數覆蓋。所有不使用var定義的變數都視為全域性變數
3、函式作用域和宣告提前
JavaScript的函式作用是指在函式內宣告的所有變數在函式體內始終是有定義的,也就是說變數在宣告之前已經可用
宣告提前(hoisting)
,即JavaScript函式裡的所有宣告(只是宣告,但不涉及賦值)都被提前到函式體的頂部,而變數賦值操作留在原來的位置。如下面例子:註釋:宣告提前
是在JavaScript引擎的預編譯時進行,是在程式碼開始執行之前。
var scope = 'global';
function f(){
console.log(scope);
var scope = 'local';
console.log(scope);
}
由於函式內宣告提升,所以上面的程式碼實際上是這樣的
var scope = 'global'; function f(){ var scope; //變數宣告提升到函式頂部 console.log(scope); scope = 'local'; //變數初始化依然保留在原來的位置 console.log(scope); }
經過這樣變形之後,答案就就非常明顯了。由於scope在第一個console.log(scope)語句之前就已經定義了,但是並沒有賦值,因此此時scope的指是undefined
.第二個console.log(scope)語句之前,scope已經完成賦值為’local’,所以輸出的結果是local
。
函式宣告提升
1、函式的兩種建立方式
- 函式宣告
- 函式表示式
函式宣告語法
f('superman');
function f(name){
console.log(name);
}
執行上面的程式,控制檯能打印出supemran
。函式表示式語法
f('superman'); var f= function(name){ console.log(name); }
執行上面的程式碼,會報錯Uncaught ReferenceError: f is not defined(…)
,錯誤資訊顯示說f沒有被定義。
為什麼同樣的程式碼,函式宣告和函式表示式存在著差異呢?
這是因為,函式宣告有一個非常重要的特徵:函式宣告提升
,函式宣告語句將會被提升到外部指令碼或者外部函式作用域的頂部(是不是跟變數提升非常類似)。正是因為這個特徵,所以可以把函式宣告放在呼叫它的語句後面。如下面例子,最終的輸出結果應該是什麼?:
var getName = function(){
console.log(2);
}
function getName (){
console.log(1);
}
getName();
可能會有人覺得最後輸出的結果是1
。讓我們來分析一下,這個例子涉及到了變數宣告提升
和函式宣告提升
。正如前面說到的函式宣告提升,函式宣告function getName(){}
的宣告會被提前到頂部。而函式表示式var getName = function(){}
則表現出變數宣告提升。因此在這種情況下,getName也是一個變數,因此這個變數的宣告也將提升到底部,而變數的賦值依然保留在原來的位置。需要注意的是,函式優先,雖然函式宣告和變數宣告都會被提升,但是函式會首先被提升,然後才是變數。因此上面的函式可以轉換成下面的樣子:
function getName(){ //函式宣告提升到頂部
console.log(1);
}
var getName; //變數宣告提升
getName = function(){ //變數賦值依然保留在原來的位置
console.log(2);
}
getName(); // 最終輸出:2
所以最終的輸出結果是:2
。在原來的例子中,函式宣告雖然是在函式表示式後面,但由於函式宣告提升到頂部,因此後面getName又被函式表示式的賦值操作給覆蓋了,所以輸出2
。
如果函式宣告和變數宣告同名,咋辦呢?
再來看下面這個例子:
foo();
function foo() {
console.log('foo');
}
var foo = 2;
// 執行結果為: foo
其實上面的執行過程 可以理解為:
function foo() {
console.log('foo');
}
var foo;
foo();
foo = 2;
// 執行結果為: foo
那麼怎麼驗證是不是上面的過程呢? 看下面證明
function foo() {
console.log('foo');
}
var foo;
console.log(typeof(foo)); // function
foo();
console.log(typeof(foo)); // function
foo = 2;
console.log(typeof(foo)); // number
foo();
console.log(typeof(foo)); // Uncaught TypeError: foo is not a function
即:函式宣告提升 高於 變數宣告提升,在同時聲明瞭同名的函式和變數 且 變數未被賦值時,此名(foo)仍然指向函式
--------------------- 作者:前端超人 來源:CSDN 原文:https://blog.csdn.net/qq673318522/article/details/50810650?utm_source=copy 版權宣告:本文為博主原創文章,轉載請附上博文連結!