javascript
JavaScript作用域解析以及例题
?作用域是對于JavaScript執行順序理解中非常關鍵的一環,也是面試題中經常出現的,因為其靈活程度,很多新手在這里吃盡苦頭。所以出一篇簡單的教程教大家如何快速掌握JavaScript作用域的使用的。
?這里我們先拋棄ES6中的let const等聲明方式,雖然他讓JavaScript嚴謹性變強,但是我們還是需要先拋棄他們,理解這其中的細節之處,到時候無論面試還是開發,都能夠避免很多潛在問題。
什么是作用域
?作用域決定了這些變量的可訪問性(可見性)。
?也就是說我在程序的任意位置什么一個變量,這個變量在程序的那些位置有效可以訪問,哪些位置無效不可訪問都是作用域所決定的。而變量在JavaScript中聲明的方式有多種,如var聲明,函數聲明和參數聲明。
var a = 0; // var聲明變量function a(){} //函數聲明方式function fn(a){} //參數a為參數聲明?當然還有一種特殊情況,如果是這樣算什么聲明了?
var a = function(){} //這也是var聲明 只不過是函數賦值給變量a?而變量聲明之后實際上是在內存中開辟一塊空間,用來存儲這個變量所表示的數據。而JavaScript不像C/C++一樣,對于內存的申請釋放是需要手動的,JavaScript的內存控制都是全自動的,也就是說自動申請,自動銷毀。所以這就是為什么這個變量可能在某一個塊能訪問,因為內存沒有銷毀,但是如果銷毀了,那么程序就自然而然訪問不到這個變量了。所以這就是作用域的作用,也就是JavaScript變量可訪問性控制。
作用域的分類
?JavaScript的作用域只有兩種:
- 全局作用域
- 函數作用域
全局作用域與全局變量
?在非函數內代碼內都是全局作用域,一般在頁面的script標簽內居多。而在全局作用域并且非函數內聲明的變量就叫做全局變量了。全局變量很好理解,也就是在頁面中所有的腳本和函數都能訪問到他,包括其他script腳本內。
<script type="text/javascript">var a = 0; // 全局作用域中聲明全局變量a function b(){} // 全局作用域內聲明的函數bconsole.log(a); // 打印0 可訪問全局變量a </script> <script type="text/javascript">console.log(a); // 打印0 可訪問全局變量a </script>函數作用域
?函數作用域顧名思義就是在函數內聲明的變量了,并且這些變量只能在函數內訪問,一旦是函數外部就無法訪問了。
function fn(){var a = 0;console.log(a);// 執行函數的時候會打印在函數內部聲明的變量a, 值為0 } fn(); console.log(a);// 報錯:變量a未定義 原因:無法在函數外部訪問函數內部的變量?從概念上來說還是很好懂得,但是凡事就怕萬一,也就是我們所說的特殊情況。由于JavaScript是一門動態類型語言,所以對于類型的定義要求并不嚴格,可以隨時修改。并且,也是可以允許變量重名的情況,雖然這種設定并不合理(這也是很多JAVA,C++等語言的開發者很討厭JavaScript的原因),但是我們作為JavaScript學習者,一定要學會處理這些特殊情況,因為JavaScript不會因為不合理而報錯,所以我們來看一些特殊情況。
function fn(a){var afunction a(){} } //提問: 改函數作用域里面的變量a是指哪個聲明方式 函數? 參數? var??在以上例子中函數fn中作用域出現了3個不同方式的同一名稱變量a,如果我們在函數內調用a的時候,a指向的是優先級關系的??偟膩碚f就是函數 > 參數 > var。也就是說,如果三者都存在,那么a指向函數,如果只存在參數和var,那么a指向為參數。
作用域的解析順序
?重點來了,因為JavaScript沒有類的存在(ES6中的class是作為語法糖而存在,本質不是真正的類),也沒有代碼塊的說法,所以它的執行順序有那么一絲不同的。大體一致,執行順序為從上到下,但是在執行順序執行還有一個過程叫做詞法解析,即在程序執行之前解析代碼中的變。
var a = 33; function fu(a) {console.log(a);var a = 123;console.log(a);function a() {console.log(a);}console.log(b);var b = function () {}console.log(b);function b() { } } console.log(a) fu(2);詞法解析的核心目的就是在執行某一個作用域代碼之前的變量提取,以上面一個代碼為例子,他擁有兩個作用域,一個是全局,另外一個是fu函數作用域。代碼在執行過程中第一步就是執行全局作用域,而全局作用域的第一步就是詞法解析,解析步驟: 詞法解析:提取全局作用域中的變量,也就是var關鍵字聲明的變量a和function聲明的函數b 代碼執行: 代碼執行的規律就是從上到下,而且要注意的是,賦值也算是代碼的執行
- 33數字賦值給變量a > 第一個行代碼
- console.log(a) > 此時控制臺輸出的這個a在全局中是屬于全局作用域中var關鍵字聲明的變量a,在上一步的時候被賦值了33,所以此處打印33
- 執行函數fu,并且傳入參數2。
這里需要注意的是,函數聲明不是語句執行,是屬于聲明也就是在詞法解析時候的步驟,所以在代碼執行的步驟是直接跳過的
?至此,全局作用的代碼全部執行完畢下一步就是函數作用域的代碼了,因為在代碼執行的第3步,執行了函數fu,此刻函數內的作用域即生效了(函數如果沒有執行,函數內的任何語句都不要關心,可以直接忽略不計)
function fu(a) {console.log(a);var a = 123;console.log(a);function a() {console.log(a);}console.log(b);var b = function () {}console.log(b);function b() { } }?進入到函數作用域,步驟跟在全局是一致的。
詞法解析:
函數內有提取參數a,var聲明變量a,函數a,var聲明變量b和函數聲明b 因為第一步出現了同名變量,所以需要要確定變量唯一指向,依據函數 > 參數 > var的原則,變量a為函數,變量b為函數 代碼執行:
- 第一行控制臺打印變量a,之前在詞法解析步驟確認a為函數,所以這里打印 [Function: a]
- 第二行給變量a賦值123,第三行再打印a就從函數變成了值123。因為JavaScript是屬于動態類型語言,所以不同類型數值賦值不會有錯誤
- 第四行聲明函數,是屬于詞法解析步驟,可忽略。
- 接著就是控制臺打印b,詞法解析過程中b為函數。所以這處打印為函數
- 下一行為變量b被賦值為函數,這時是一個新的空函數,但本質還是函數,所以下一行打印b仍然為函數[Function: b]
以上就是對作用域的基本用法,當然一個案例不能概括所有的情況,還是需要大家大量練習才會熟練。下面有一些練習題,各位可以去練練
var a = 123; function fun(){console.log(a);var a = 456;console.log(a); } fun(); console.log(a);//---------------------------------------------------var b = 123; function fun(){console.log("b = "+b);b = 456; } fun(); console.log("b = "+b);//---------------------------------------------------var c = 123; function fun(c){console.log("c = "+c);c = 456; } fun(); console.log("c = "+c);//---------------------------------------------------var d = 123; function fun(d){console.log("d1 = "+d);d = 456; } fun(789); console.log("d = "+d);//--------------------------------------------------- var a = 33; function fu(a) {console.log(a);var a = 123;console.log(a);function a() {console.log(a);}console.log(b);var b = function () { }console.log(b);function b() { } } console.log(a) fu(2);//--------------------------------------------------- function test(a, b) {console.log(a);c = 0;var c;a = 3;b = 2;console.log(b);function b() { }function d() { }console.log(d); } test(2);//---------------------------------------------------fn(); console.log(a); var a = 10; console.log(a); function fn(){var a = 1;}? 要寫出每個例子的打印的步驟以及解析步驟
總結
以上是生活随笔為你收集整理的JavaScript作用域解析以及例题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Clinet/Server在工作线程中刷
- 下一篇: Python对网页信息进行爬取并对标题分