javascript 作用域鏈與執行環境
作用域、作用域鏈、執行環境、執行環境堆疊以及this的概念在javascript中非常重要,本人經常混淆,這裡梳理一下;
局部作用域函數內部的區域,全域作用域就是window;
作用域鏈取決於函數被宣告時的位置,解析標識符的時候就先找目前作用域,再向外查找,直到全局,這樣一個順序;和函數在哪裡調用無關;
執行環境就是函數可訪問的資料和變數的集合,也就是函數的作用域鏈上的所有資料和變數;
執行環境堆疊就是根據程式碼執行順序,各執行環境按照堆疊的形式逐層訪問,並且用完了退出來扔掉;如果當前執行環境(存放目前作用域鏈裡的資料和變數)找不到變量,那就是找不到了,不會往之前的那個執行環境查找,它和作用域鍊是不同的;
作用域
JavaScript沒有區塊級作用域的概念,只有函數級作用域:變數在宣告它們的函數體及其子函數內是可見的。
作用域就是變數和函數的可存取範圍,控制變數和函數的可見性與生命週期,在JavaScript中變數的作用域有全域作用域和局部作用域。
變數沒有在函數內宣告或宣告的時候沒有帶var就是全域變量,擁有全域作用域;
<script type="text/javascript"> function test1(){ a = 1;//全局变量,只有在当前函数运行时,才有效 } test1(); console.log(a);//1 注意test1函数必须运行,不然找不到a </script>
-
全域變數可以當做window物件的屬性用,他們是一樣的;
<script type="text/javascript"> var b = 1;//全局变量 console.log(b === window.b); //true 全局变量可以当做window对象的属性用,他们是一样的; </script>
window物件的所有屬性都有全域作用域,在程式碼任何地方都可以存取;
函數內部聲明的變數就是局部變量,只能在函數體內使用,函數的參數雖然沒有使用var但仍然是局部變數。
<script type="text/javascript"> var c = 1;//全局变量// console.log(d);//ReferenceError: d is not defined 引用错误,当前作用域就是最外层作用域,依然找不到d function test2(d){ console.log(c); //1 全局变量,哪都可以访问;(先找当前作用域,找不到,就向外层作用域找,直到window最外层,找到了) console.log(d);//3 形参是局部变量,只有当前作用域下可以访问 } test2(3); </script>
作用域鏈
作用域鏈取決於函數被宣告時的位置,解析標識符的時候就先從目前作用域開始找,在當前當作用域中無法找到時,引擎就會在外層嵌套的作用域中繼續查找,直到找到該變量,或抵達最外層的作用域(也就是全域作用域)為止;它的路線已經被定死了,和函數在哪裡運行無關;
<script type="text/javascript"> var a = 1; var b = 2; var c = 3; var d = 4; function inner(d) {//它的作用域链是inner---全局 var c = 8; console.log(a);//1 当前作用域找不到a,去全局作用域找到了a=1 console.log(b);//2 当前作用域找不到b,去全局作用域找到了b=2 console.log(c);//8 当前作用域找到了c=8 console.log(d);//7 当前作用域找到了d=7,形参也是局部作用域 // console.log(e);//ReferenceError: e is not defined 引用错误,找不到e, 它的作用域链是inner---全局 console.log(a+b+c+d);//18 } function outter(e) { var a = 5;//inner()的作用域链是inner---全局,所以这个a相当于无效 var b = 6;//inner()的作用域链是inner---全局,所以这个a相当于无效 inner(7); } outter(999);//这个999无效,里面的e根本找不到 </script>
#在多層的嵌套作用域中可以定義同名的標識符,這叫作「遮蔽效應”,內部的標識符“遮蔽”了外部的標識符
透過window.a這種技術可以存取那些被同名變數所遮蔽的全域變數。但非全域的變數如果被遮蔽了,無論如何都無法被存取;
<script type="text/javascript"> var a = 'Lily'; var b = 'Lucy'; function outer() { var b = 'Jesica'; var c = 'Susan'; function inner(c) { console.log(a);//Lily console.log(window.b);//Lucy console.log(b);//Jesica console.log(c);//Jenifer } inner('Jenifer'); } outer(); </script>
執行環境
執行環境(execution context),也叫執行上下文。每個執行環境都有一個變數物件(variable object),保存函數可存取的所有變數和資料(也就是函數的作用域鏈上的所有資料和變數)。我們的程式碼存取不到它,它是給引擎使用的;
執行環境棧,當執行進入一個函數時,函數的執行環境就會被推入一個堆疊中。而在函數執行完之後,棧將其執行環境移除,它裡面的變數和資料會被標記清除,等待垃圾回收,再把控制權回傳給先前的執行環境。 javascript程式中的執行正是由這個機制控制著;
需要注意的是如果當前執行環境(存放當前作用域鏈裡的資料和變數)找不到變量,那就是找不到了,不會往之前的那個執行環境查找,和作用域鍊是不一樣的;
程式碼的執行順序也不全是一行一行的執行,而是和函數的呼叫順序有關:
程式碼進入全域執行環境,全域執行環境放入環境堆疊;
當執行到一個函數時,就把這個函數的執行環境被推入到環境堆疊頂端,之前的執行環境往後;
#全域執行環境先進入,所以一直在底端;就跟堆疊的概念差不多;
函數執行完之後,再把它的執行環境從作用域鏈頂端移除,它保存的資料和函數都被標記清除,等待垃圾回收;
控制權交給先前的執行環境,繼續往下執行;
#當頁面關閉時,全域執行環境才會銷毀;
#程式碼執行進入全域執行環境,並對全域執行環境中的程式碼進入宣告提升;
執行第2行,賦值a=1; 然後第3行賦值b=2; 則第4行賦值c=3; 則第5行賦值d=4;
執行第20行,呼叫outer(999)函數,然後進入outer(999)函數執行環境,宣告提升,並將實參999傳給形參e;現在環境堆疊中有兩個執行環境,outer(999)是目前執行環境;
執行第16行,賦值a=5; 則第17行賦值b=6;
#執行第18行,呼叫inner(7)函數,然後進入inner(7)函數執行環境,宣告提升,並將實參7傳給形參d;
執行第7行,賦值c=8; 然後運算並輸出;
#程式碼最佳化
由於在作用域鏈上尋找變數是需要消耗性能的,我們應該盡快的找到變量,所以在函數多層嵌套的時候,我們應盡可能的使用函數內部的局部變量;
我們在函數內部使用全局變量可以說是一種跨作用域操作,如果某個跨作用域的值在函數的內部被多次使用,那麼我們就把它儲存到局部變數裡,這樣可以提高效能。
以上是javascript 作用域鏈與執行環境的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

typedef struct 在 C 語言中用於建立結構體類型別名,簡化結構體使用。它透過指定結構體別名將一個新的資料類型作為現有結構體的別名。優點包括增強可讀性、程式碼重複使用和類型檢查。注意:在使用別名前必須定義結構體,別名在程式中必須唯一且僅在其宣告的作用域內有效。

Java 中的變數期望值異常可以透過以下方法解決:初始化變數;使用預設值;使用 null 值;使用檢查和賦值;了解局部變數的作用域。

JavaScript 閉包的優點包括維持變數作用域、實作模組化程式碼、延遲執行和事件處理;缺點包括記憶體洩漏、增加了複雜性、效能開銷和作用域鏈影響。

C++ 中的 #include 預處理器指令將外部來源檔案的內容插入到目前原始檔案中,以複製其內容到目前原始檔案的相應位置。主要用於包含頭文件,這些頭文件包含程式碼中所需的聲明,例如 #include <iostream> 是包含標準輸入/輸出函數。

C++智慧指標的生命週期:建立:分配記憶體時建立智慧指標。所有權轉移:透過移動操作轉移所有權。釋放:智慧指標離開作用域或被明確釋放時釋放記憶體。物件銷毀:所指向物件被銷毀時,智慧型指標成為無效指標。

可以。 C++ 允許函數巢狀定義和呼叫。外部函數可定義內建函數,內部函數可在作用域內直接呼叫。巢狀函數增強了封裝性、可重複用性和作用域控制。但內部函數無法直接存取外部函數的局部變量,且傳回值類型需與外部函數宣告一致,內部函數不能自遞歸。

在 Vue 中,let 和 var 宣告變數時在作用域上存在差異:作用域:var 具有全域作用域,let 具有區塊級作用域。區塊級作用域:var 不會建立區塊級作用域,let 建立區塊級作用域。重新宣告:var 允許在同一作用域內重新宣告變數,let 不允許。

智慧指針是C++專用指針,能夠自動釋放堆記憶體對象,避免記憶體錯誤。類型包括:unique_ptr:獨佔所有權,指向單一物件。 shared_ptr:共享所有權,允許多個指標同時管理物件。 weak_ptr:弱引用,不增加引用計數,避免循環引用。使用方法:使用std命名空間的make_unique、make_shared和make_weak建立智慧指標。智慧型指標在作用域結束時自動釋放物件記憶體。進階用法:可以使用自訂刪除器控制物件釋放方式。智慧型指標可有效管理動態數組,防止記憶體洩漏。
