摘要:輸出的結果為輸出的結果為提升后輸出的結果為重新定義了變量輸出的結果為如果定義了相同的函數變量聲明,后定義的聲明會覆蓋掉先前的聲明,看如下代碼輸出練習的值是多少的值是多少第二題的解析請看這里參考資料文章文章中文版鏈接文章推薦文章變量提升
JavaScript 變量聲明提升
一個小例子原文鏈接
先來看個例子:
console.log(a); // undefined var a = 2; console.log(a); // 2
為什么是這樣的結果呢?這是因為 JavaScript 代碼在執行之前會有一個 預解析 階段,在這個階段,解釋器會將所有 變量聲明 和 函數聲明 提升到他們各自的作用域頂部。
注:變量聲明提升只是預解析階段的一部分行為!
如果變量在函數體內聲明,它的作用域是函數作用域(function-level scope)。否則,它就是全局作用域。
繼續上面的例子,因為這個預解析階段,上面的代碼會被解釋器預解析成下面的代碼:
var a; console.log(a); // undefined a = 2; console.log(a); // 2變量的聲明
在 ES6 之前,通常通過 var 來聲明一個變量,但是 ES6 發布后,又新添了2個關鍵字來聲明一個變量:let 和 const。
var 聲明了一個變量,這個變量的作用域是當前執行位置的上下文:一個函數的內部(聲明在函數內)或者全局(聲明在函數外)
let 聲明了一個塊級域的局部變量,并且它聲明的變量只在所在的代碼塊內有效
const 聲明了一個只讀的塊級域的常量,并且它聲明的常量也只在所在的代碼塊內有效
{ // 代碼塊 var a = 1; let b = 2; const c = 3; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 } console.log(a); // 1 console.log(b); // 報錯,ReferenceError: b is not defined(…) console.log(c); // 未執行, 因為上面語句出錯,所以這條語句不再執行,如果上面的語句不報錯,那么這里就會報錯
(function (){ var a = 1; let b = 2; const c = 3; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 })(); // 為了方便,這里使用了自執行函數 console.log(a); // 報錯,ReferenceError: a is not defined(…) console.log(b); // 未執行 console.log(c); // 未執行
let const 不像 var 那樣會發生“變量提升”現象。
console.log(a); // 報錯,ReferenceError: a is not defined let a = 2; console.log(a); // 待執行
console.log(a); // 報錯,ReferenceError: a is not defined const a = 2; console.log(a); // 待執行
變量聲明提升(Variable hoisting)ES6明確規定,如果區塊中存在let和const命令,這個區塊對這些命令聲明的變量,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量,就會報錯。
提升(hoisting)影響了變量的生命周期,一個變量的生命周期包含3個階段:
聲明 - 創建一個新變量,例如 var myValue
初始化 - 用一個值初始化變量 例如 myValue = 150
使用 - 使用變量的值 例如 alert(myValue)
當代碼按照這三個步驟的順序執行的時候,一切看起來都很簡單,自然。
變量提升的部分只是變量的聲明,賦值語句和可執行的代碼邏輯還保持在原地不動
console.log(a); // undefined var a = 111; function fun(){ console.log(a); // undefined var a = 222; console.log(a); // 222 } fun(); console.log(a); // 111 // -------------- //變量提升后 function fun(){ var a; console.log(a); // undefined a = 222; console.log(a); // 222 } var a; console.log(a); // undefined a = 111; fun(); console.log(a); // 111
在基本的語句(或者說代碼塊)中(比如:if語句、for語句、while語句、switch語句、for...in語句等),不存在變量聲明提升
var a = "aaa"; { console.log(a); // aaa var a = "bbb"; } console.log(a); // bbb //--------------- var a = "aaa"; if (true) { console.log(a); // aaa var a = "bbb"; } console.log(a); // bbb //--------------- var a = "aaa"; for(let x in window){ console.log(a); // aaa var a = "bbb"; break; } console.log(a); // bbb函數聲明提升(Function Hoisting)
函數聲明(function declarations) 和 函數表達式(function expressions)在語法上其實是等價的,但是有一點不同,就是 JavaScript 引擎 加載他們的方式不一樣。簡單講,就是函數聲明會被提升到其作用域頂部,而函數表達式不會。
更多細節
函數聲明會提升,但是函數表達式的函數體就不會提升了
fun(); // hello function fun(){ console.log("hello"); } // -------------- // 提升后 function fun(){ console.log("hello"); } fun(); // hello
fun(); // 報錯,TypeError: fun is not a function var fun = function(){ console.log("hello"); }; // -------------- // 提升后 var fun; fun(); // 報錯,TypeError: fun is not a function fun = function(){ console.log("hello"); };
當函數表達式的函數不再是匿名函數,而是一個有函數名的函數時,會發生什么?
foo(); // 報錯,TypeError "foo is not a function" bar(); // 有效的 baz(); // 報錯,TypeError "baz is not a function" spam(); // 報錯,ReferenceError "spam is not defined" // anonymous function expression ("foo" gets hoisted) var foo = function () {}; // function declaration ("bar" and the function body get hoisted) function bar() {}; // named function expression (only "baz" gets hoisted) var baz = function spam() {}; foo(); // 有效的 bar(); // 有效的 baz(); // 有效的 spam(); // 報錯,ReferenceError "spam is not defined"
如果一個變量和函數同名,函數聲明優先于變量聲明(畢竟函數是 JavaScript 的第一等公民),并且與函數名同名的變量聲明將會被忽略。
fun(); // 輸出的結果為111 function fun(){ console.log(111); } var fun = function(){ console.log(222); } fun(); // 輸出的結果為222 // -------------- // 提升后 function fun(){ console.log(111); } fun(); // 輸出的結果為111 fun = function(){ // 重新定義了變量 fun console.log(222); } fun(); // 輸出的結果為222
如果定義了相同的函數變量聲明,后定義的聲明會覆蓋掉先前的聲明,看如下代碼:
foo(); //輸出3 function foo(){ console.log(1); } var foo = function(){ console.log(2); } function foo(){ console.log(3); }練習
alert(foo) 的值是多少?
var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); // ? } bar();
alert(a) 的值是多少?
var a = 1; function b() { a = 10; return; function a() {} } b(); alert(a); // ?
第二題的解析請看 這里
參考資料【文章】Variable and Function Hoisting in JavaScript
【文章】JavaScript variables hoisting in details(中文版鏈接)
【文章】JavaScript Scoping and Hoisting(推薦)
【文章】JavaScript變量提升
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80247.html
摘要:但是碰到聲明提升,這種想法就會被打破。聲明一個函數進行相應的操作,會得到函數聲明提升的結果。由此可以發現變量和函數的聲明都會被提升在其他代碼的前面執行。一個普通塊內部的函數聲明通常會被提升到所在的作用域的頂部。的創建初始化和賦值均會被提升。 Javascript聲明提升 在分析聲明提升之前,我認為有必要知道的兩點: 一、引擎查詢變量的兩種方式 引擎查詢變量的方式可以分為LHS和RHS兩...
摘要:不同的是函數體并不會再被提升至函數作用域頭部,而僅會被提升到塊級作用域頭部避免全局變量在計算機編程中,全局變量指的是在所有作用域中都能訪問的變量。 ES6 變量作用域與提升:變量的生命周期詳解從屬于筆者的現代 JavaScript 開發:語法基礎與實踐技巧系列文章。本文詳細討論了 JavaScript 中作用域、執行上下文、不同作用域下變量提升與函數提升的表現、頂層對象以及如何避免創建...
摘要:變量提升什么是變量提升在函數體內聲明的變量,無論你是在函數的最底端還是中間聲明的,那么都會把該變量的聲明提升到函數的最頂端相當于第一行,但是只是提升變量的聲明,不會賦值。 1、變量提升 什么是變量提升?在函數體內聲明的變量,無論你是在函數的最底端還是中間聲明的,那么都會把該變量的聲明提升到函數的最頂端(相當于第一行),但是只是提升變量的聲明,不會賦值。 var num = 10; fu...
摘要:函數和變量相比,會被優先提升。這意味著函數會被提升到更靠前的位置。僅提升聲明,而不提升初始化。 JavaScript 函數高級——執行上下文與執行上下文棧(圖解+典型實例分析) 變量提升與函數提升 變量聲明提升 通過 var 定義(聲明)的變量,在定義語句之前就可以訪問到 值:undefined /* 面試題 : 輸出 undefined */ var a = 3 ...
摘要:變量提升需要注意兩點提升的部分只是變量聲明,賦值語句和可執行的代碼邏輯還保持在原地不動提升只是將變量聲明提升到變量所在的變量范圍的頂端,并不是提升到全局范圍,說明如下會輸出變量提升之后的效果函數聲明會提升,但是函數表達式就不了。 問題 有些朋友可能會覺得javascript的代碼是從上到下,一行一行的解釋執行的。如果按照這樣的思路,在有些情況下閱讀代碼會得到錯誤的結果,考慮以下代碼: ...
閱讀 2645·2021-09-13 10:26
閱讀 1907·2021-09-03 10:28
閱讀 1977·2019-08-30 15:44
閱讀 794·2019-08-29 14:07
閱讀 386·2019-08-29 13:12
閱讀 2144·2019-08-26 11:44
閱讀 2336·2019-08-26 11:36
閱讀 2003·2019-08-26 10:19