javascript的作用域


本文主要介紹關於javascript,前端的知識點,對【【JavaScript】(九) 作用域和預解析】和【javascript的作用域】有興趣的朋友可以看下由【香蕉卟NaNa】投稿的技術文章,希望該技術和經驗能幫到你解決你所遇的JavaScript相關技術問題。

javascript的作用域

JS

目錄 🍰 作用域1、作用域概述2、全局作用域3、局部作用域 (函數作用域)4、JS 沒有塊級作用域 🍰 變量的作用域1、變量作用域的分類2、全局變量3、局部變量4、全局變量和局部變量的區別 🍰 作用域鏈🍰 預解析🍰 變量預解析和函數預解析1、變量預解析(變量提升)2、函數預解析(函數提升)3、預解析小結 🍰 預解析案例案例一案例二

🍰 作用域 1、作用域概述

➢ 通常來說,一段程序代碼中所用到的名字並不總是有效和可用的,而限定這個名字的可用性的代碼范圍就是這個名字的作用域。
➢ 作用域的使用提高了程序邏輯的局部性,增強了程序的可靠性,減少了名字沖突。

➢ JavaScript(es6前)中的作用域有兩種:

全局作用域局部作用域(函數作用域) 2、全局作用域

➢ 作用於所有代碼執行的環境(整個 script 標簽內部)或者一個獨立的 js 文件。

3、局部作用域 (函數作用域)

➢ 作用於函數內的代碼環境,就是局部作用域。 因為跟函數有關系,所以也稱為函數作用域。

例子:


    DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document
      title> <script> // 全局作用域 var num = 666; console.log(num); function fn() {
        // 局部作用域 var num = 888; console.log(num); } fn(); 
       script> 
        head> <body> 
         body> 
          html> 

結果展示:

作用域

4、JS 沒有塊級作用域 塊作用域由 { } 包括。在其他編程語言中(如 java、c#等),在 if 語句、循環語句中創建的變量,僅僅只能在本 if 語句、本循環語句中使用,如下面的Java代碼:
if(true){
   
	int num = 233;
	system.out.print(num); // 233
}
system.out.print(num); // 報錯

➢ Js中沒有塊級作用域(在ES6之前)(ES6新增了塊級作用域)

if(true){
   
	var num = 233;
	console.log(233); //233
}
console.log(233); //233
🍰 變量的作用域 1、變量作用域的分類

➢ 在JavaScript中,根據作用域的不同,變量可以分為兩種:

全局變量局部變量 2、全局變量

➢ 在全局作用域下聲明的變量叫做全局變量(在函數外部定義的變量)。

全局變量在代碼的任何位置都可以使用在全局作用域下 var 聲明的變量是全局變量特殊情況下,在函數內不使用 var 聲明的變量也是全局變量(不建議使用)

例子:


    DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document
      title> <script> // 全局變量 var num = 11; // num就是一個全局變量 console.log(num); function fn() {
        console.log(num); // 全局變量在函數內部也可以使用 num1 = 22; // 函數內部 沒有聲明直接賦值的變量也屬於全局變量 } fn(); console.log(num1); 
       script> 
        head> <body> 
         body> 
          html> 

結果展示:

全局變量

3、局部變量

➢ 在局部作用域下聲明的變量叫做局部變量(在函數內部定義的變量)

局部變量只能在該函數內部使用在函數內部 var 聲明的變量是局部變量函數的形參實際上就是局部變量

➢ 例子(函數內部聲明的變量):


    DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document
      title> <script> function fun() {
        var num1 = 11; // num1就是局部變量 只能在函數內部使用 } fun(); console.log(num1); 
       script> 
        head> <body> 
         body> 
          html> 

結果展示:

局部變量

➢ 例子(函數的形參也可以看做是局部變量):


    DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document
      title> <script> // 注意: 函數的形參也可以看做是局部變量 function fun(aru) {
        } fun(); console.log(aru); 
       script> 
        head> <body> 
         body> 
          html> 

結果展示:

形參


➢ 函數內部 var 聲明的變量和函數的形參都是局部變量,在函數外部使用會報錯。

4、全局變量和局部變量的區別 全局變量:在任何一個地方都可以使用,只有在瀏覽器關閉時才會被銷毀,因此比較占內存局部變量:只在函數內部使用,當其所在的代碼塊被執行時,會被初始化;當代碼塊運行結束后,就會被銷毀,因此更節省內存空間 🍰 作用域鏈 只要是代碼,就至少有一個作用域寫在函數內部的局部作用域如果函數中還有函數,那么在這個作用域中就又可以誕生一個作用域根據在內部函數可以訪問外部函數變量的這種機制,用鏈式查找決定哪些數據能被內部函數訪問,就叫做作用域鏈作用域鏈:采取就近原則的方式來查找變量最終的值。

例子:


    DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document
      title> <script> // 作用域鏈 : 內部函數訪問外部函數的變量,采取的是鏈式查找的方式來決定取那個值 這種結構我們稱為作用域鏈 就近原則 var num = 66; function fun1(){
        // 外部函數 var num = 88; function fun2(){
        // 內部函數 console.log(num); } fun2(); } fun1(); 
       script> 
        head> <body> 
         body> 
          html> 

結果展示:

作用域鏈

🍰 預解析

➢ JavaScript 代碼是由瀏覽器中的 JavaScript 解析器來執行的。JavaScript 解析器在運行 JavaScript 代碼的時候分為兩步:預解析和代碼執行。

預解析:在當前作用域下, JS 代碼執行之前,瀏覽器會默認把帶有 var 和 function 聲明的變量在內存中進行提前聲明或者定義。代碼執行: 從上到下執行JS語句。

➢ 預解析只會發生在通過 var 定義的變量和 function 上。

🍰 變量預解析和函數預解析 1、變量預解析(變量提升)

➢ 預解析也叫做變量、函數提升。
➢ 變量提升: 變量的聲明會被提升到當前作用域的最上面,變量的賦值不會提升。

例子:


    DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document
      title> <script> // 變量預解析 console.log(num1); // undefined var num1 = 10; // 相當於執行了以下代碼 /* var num; // 1、變量提升,此時不賦值 console.log(num); // 2、變量提升之后,按照代碼執行順序,從上往下執行 num = 10; // 3、此時才進行變量賦值 // 因為輸出操作在賦值前,輸出操作執行時,變量還沒有賦值,所以輸出的是undefined) */ var num2 = 20; console.log(num2); // 20 // 相當於執行了以下代碼 /* var num2; // 1、變量提升,此時不賦值 num2 = 22; // 2、變量提升之后,按照代碼執行順序,從上往下執行,此時是賦值操作 console.log(num2); // 3、變量提升之后,按照代碼執行順序,從上往下執行,此時是輸出操作 // 因為賦值操作在輸出之前,變量已完成賦值操作后再被輸出,所以輸出的是變量被賦的值 */ 
       script> 
        head> <body> 
         body> 
          html> 

結果展示:

變量提升

2、函數預解析(函數提升)

➢ 函數提升: 函數的聲明會被提升到當前作用域的最上面,但是不會調用函數。

例子:


    DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document
      title> <script> fn(); function fn() {
        console.log(666); // 666 } // 相當於執行了以下代碼 /* function fn() { // 1、函數提升 console.log(666); } fu(); // 2、調用函數,正常輸出666 */ fun(); var fun = function() {
        console.log(22); // 報錯 } // 相當於執行了以下代碼 /* var fun; // 1、var定義的,是一個變量,此處先進行變量提升 fun(); // 2、該例子中的是匿名函數,不進行函數提升,所以變量提升結束后,按照代碼執行順序,從上往下執行,此時是調用函數,可是該函數在調用前並沒有進行定義,所以會報錯 fun = function() { // 3、此時才進行變量賦值 console.log(22); } */ // 所以 函數表達式調用必須寫在函數表達式的下面 
       script> 
        head> <body> 
         body> 
          html> 

結果展示:

函數提升

3、預解析小結

1、js 引擎運行 js 分為兩步:預解析和代碼執行
(1)預解析:js 引擎會把 js 里面所有的 var (定義的變量) 還有 function (命名函數)提升到當前作用域的最前面
(2)代碼執行:按照代碼書寫的順序從上往下執行
2、預解析分為 變量預解析(變量提升)和 函數預解析(函數提升)
(1)變量提升:就是把所有的變量聲明提升到當前的作用域最前面,不提升賦值操作
(2)函數提升:就是把所有的函數聲明提升到當前作用域的最前面,不調用函數

🍰 預解析案例 案例一

    DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document
      title> <script> var a = 11; f1(); function f1() {
        var b = 22; console.log(a); console.log(b); var a = '233'; } // 相當於以下代碼 /* var a; // 1、變量提升 function f1() { // 2、函數提升 var b; // 3、函數內部 變量提升 var a; // 4、函數內部 變量提升 b = 22; // 5、函數內部,變量賦值 console.log(a); // 此時a定義了還沒有賦值,所以函數被調用時輸出undefined console.log(b); // b已被賦值,所以函數被調用時輸出b的值 22 a = '233'; // 此時函數內部的a才被賦值 } a = 11; // 函數外部變量賦值 f1(); // 調用函數 */ 
       script> 
        head> <body> 
         body> 
          html> 

結果展示:

案例一

案例二

    DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document
      title> <script> f1(); console.log(c); console.log(b); console.log(a); function f1() {
        var a = b = c = 8; console.log(a); console.log(b); console.log(c); } // 以下代碼 /* function f1() { // 函數提升 var a; // 函數內部 變量提升 a = b = c = 8; // 函數內部 變量賦值 // var a = b = c = 8 相當於 var a = 8; b = 8; c = 8; b 和 c 直接賦值 沒有var聲明,當全局變量看 // 集體聲明 var a = 8, b = 8, c = 8; console.log(a); // a已被賦值,所以函數被調用時輸出a的值 8 console.log(b); // b已被賦值,所以函數被調用時輸出b的值 8 console.log(c); // c已被賦值,所以函數被調用時輸出c的值 8 } f1(); // 調用函數 console.log(c); // 函數內部c沒有用var定義,相當於全局變量,且c在函數中已被賦值,所以輸出c的值 8 console.log(b); // 函數內部b沒有用var定義,相當於全局變量,且b在函數中已被賦值,所以輸出b的值 8 console.log(a); // a是局部變量,在函數外部使用會報錯 */ 
       script> 
        head> <body> 
         body> 
          html> 

結果展示:

預解析案例二

本文《【JavaScript】(九) 作用域和預解析》版權歸香蕉卟NaNa所有,引用【JavaScript】(九) 作用域和預解析需遵循CC 4.0 BY-SA版權協議。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: