主頁 > 企業開發 > JS閉包和作用域(必學知識點總結)

JS閉包和作用域(必學知識點總結)

2023-01-28 08:05:43 企業開發

目錄
  • 閉包和作用域
    • 變數宣告
    • 變數和函式的宣告提升
    • 作用域和作用域鏈
    • 執行背景關系
    • 閉包
    • 垃圾回識訓制

閉包和作用域


變數宣告

var 宣告特點

  1. 在使用var宣告變數時,變數會被自動添加到最接近的背景關系
  2. var存在宣告提升var宣告會被拿到函式或全域作用域的頂部,位于作用域中所有代碼之前,
  3. 可多次重復宣告,而重復的var宣告則會被忽略

let 宣告特點

  1. let宣告存在塊級作用域

  2. let宣告(創建程序)存在提升,但由于暫時性死區(temporal dead zone),無法在let宣告之前去使用變數

  3. 在同一作用域內無法重復宣告,重復的let宣告會拋出SyntaxError錯誤

const 宣告特點

  1. const宣告存在塊級作用域
  2. const一旦宣告后在其生命周期內都無法重新賦予新值
  3. 其余與let宣告一致

變數和函式的宣告提升

變數宣告與函式宣告都存在提升,可以記住以下幾個點:

  1. 變數宣告中由var定義的變數會提升到其所在作用域的頂部,
  2. 變數宣告中letconst提升效果一致,即由其定義的變數都會在創建程序被提升,但在初始化階段被暫時性死區所扼殺
  3. 函式宣告優先于變數宣告,而函式運算式則會作為一個變數提升,其提升效果取決于用let還是var定義,

變數和函式的具體宣告情況如下:

  • let的「創建」程序被提升了,但是初始化沒有提升,
  • var的「創建」和「初始化」都被提升了,
  • function的「創建」「初始化」和「賦值」都被提升了,

來看這樣三段代碼:

第一段:var 變數宣告效果

// 第一段
console.log(a) // 輸出:undefined
var a = 10

上面代碼運行后的實際情況如下:

var a // y 變數宣告提升到其所在作用域的頂部
console.log(a)
a = 10

第二段:let變數宣告效果(const與其一致)

// 第二段
{
    console.log(x) // 產生暫時性死區,無法訪問變數,
    // 報錯內容:Uncaught ReferenceError: Cannot access 'x' before initialization
    // 在值初始化之前無法訪問 x ,即變數在初始化階段被暫時性死區所扼殺
    let x = 10
}

第三段:函式宣告與函式運算式宣告效果

// 第三段:
var foo = function () {
    console.log('我是函式運算式')
}
function foo() {
    console.log('我是函式宣告')
}
foo()
// 按照我們常規思維去思考一下,也許會輸出'我是函式宣告',
// 但去執行一下,輸出:'我是函式運算式'

上面代碼運行后的實際情況如下:

function foo() {  // foo 作為函式宣告被提升了
    console.log('我是函式宣告')
}
var foo // foo 作為 var 變數宣告被提升了 
foo = function () {
    console.log('我是函式運算式')
}
foo()
// 其中函式宣告優先于變數宣告,這也就解釋了為什么不會輸出'我是函式宣告',

作用域和作用域鏈

作用域

作用域分類:

  1. 全域作用域
  2. 函式作用域(function函式體內 )
  3. 塊級作用域(letconst宣告存在塊級作用域)
// 全域作用域

function foo() {
    // 函式作用域
}

{
    let c = 30
    // 塊級作用域
}

詞法作用域:JavaScript會利用詞法分析器分析我們書寫的代碼,從而依據變數和函式的命名位置來動態生成不同的作用域,即我們在定義變數或函式的時候,就已經決定了它們之間在不同作用域上的關系,

作用域鏈

作用域鏈由執行背景關系中的變數物件逐級構成,

學習要點:

  1. 作用域鏈的用途,是保證對執行環境有權訪問的所有變數和函式的有序訪問,
  2. 每個環境都可以逐級向上搜索作用域鏈查詢變數和函式名;但任何環境都不能通過向下搜索作用域鏈,
  3. 自由變數:未在當前作用域定義的變數,自由變數會按照作用域鏈的查找機制,逐級向上查找與之對應的變數

執行背景關系

執行背景關系保存著變數物件,作用域鏈和this

學習要點:

  1. 所有通過var定義的全域變數會函式都會成為window物件的屬性和方法,但使用letconst的宣告的全域變數和函式不會定義在全域背景關系中,
  2. 每個函式被呼叫時都會產生一個執行背景關系,這個執行背景關系會被推入堆疊,在函式執行完畢后,該執行背景關系會在堆疊彈出,將控制權返還給之前的執行背景關系,
  3. 當前作用域鏈中的第一個變數物件來自上一個背景關系,下一個變數物件來自再上一個背景關系,以此類推直至全域背景關系,

執行背景關系分類:

  1. 全域背景關系 (window物件)
  2. 函式背景關系
  3. eval()背景關系

來看這樣一段代碼:

let a = 10
function sum() {
    let b = 20
    function add() {
        let c = 30
        console.log(a + b + c)
    }
    add()
}
sum()

執行背景關系內容如下:

全域執行背景關系:
[ 作用域鏈:[], 變數物件:[ a, sum ], this: window ]

sum 函式執行背景關系:
[ 作用域鏈:[ 全域變數物件:[ a, sum ] ], 變數物件:[ b, add ] , this: window ]

add 函式執行背景關系:
[ 作用域鏈:[ add函式的變數物件: [ b, add ], 全域變數物件:[ a, sum ] ], 變數物件:[c] , this: window ]

入堆疊程序

  1. 首先呼叫sum函式將其推入堆疊,產生了第一個函式執行背景關系,

  2. 緊接著sum函式內部又呼叫add函式,于是又將其函式推入堆疊,產生了第二個函式執行背景關系,

出堆疊程序

  1. add函式執行完畢后將其彈出堆疊,控制權交給sum函式,

  2. sum函式執行完畢后將其彈出堆疊,控制權交給全域背景關系,

  3. 當瀏覽器關閉后,全域背景關系會出堆疊,


閉包

閉包定義:在一個嵌套函式里,內部函式可以訪問外部函式的變數,

閉包應用:封裝物件的私有屬性和方法,即對資料作隱藏和封裝,防止污染全域變數

閉包作用:多個閉包可以共享相同的函式定義,但卻保存了不同的詞法環境,

來看這樣三段代碼:

// 前置知識:setTimeout在事件回圈機制中作為宏任務,for回圈屬于微任務,
// 宏任務會在微任務之后執行,即我們的for回圈會先一步于setTimeout結束,
for (var i = 0; i < 10; i++) {
    setTimeout(function () {
        console.log(i)
    }, 3000)
} // 輸出結果:輸出10次 10 !
// 每回圈一次,都共享了相同的詞法環境(全域作用域),

我們給setTimeout套一個立即執行函式,如下:

for (var i = 0; i < 10; i++) {
    (function (i) { // 我們的閉包函式,相對于全域環境
        setTimeout(function () {
            console.log(i) // 內部函式訪問了外部函式的變數
        }, 3000)
    })(i)
} // 輸出結果:3秒后輸出 0 1 2 3 4 5 6 8 9
// 每回圈一次,立即執行函式就創建了不同的詞法環境(塊級作用域),

我們換另一種形式去驗證一下:

for (var i = 0; i < 10; i++) {
    let a = function (i) { // 我們的閉包函式,相對于全域環境
        setTimeout(function () {
            console.log(i) // 內部函式訪問了外部函式的變數
        }, 3000)
    }
    a(i)
} // 輸出結果:同樣3秒后輸出 0 1 2 3 4 5 6 8 9 

特別注意:不能濫用閉包,因為閉包在處理速度和記憶體消耗方面對腳本性能具有負面影響,


垃圾回識訓制

作用:垃圾回收程式會跟蹤記錄需要使用的變數和不需使用的變數,自動進行記憶體管理實作記憶體分配和閑置資源回收,

記憶體的生命周期:

  1. 分配你所需要的記憶體
  2. 使用分配到的記憶體(讀、寫)
  3. 不需要時將其釋放

在瀏覽器的發展史上,主要有兩種標記策略:參考計數和標記清理,

參考計數

基本原理:當首次宣告變數并賦一個參考型別值時,會將這個值的參考次數設定為1,當這個值被賦給其他變數時,這個值的參考次數會再加1,當這個值被其他值所覆寫時,參考次數會減1,直到參考次數為0時,垃圾回識訓制則會“上門回收”這個值

來看這樣一段代碼:

let a = { name: '小紅' } // 首次值賦變數,參考計數為 1
let b = a // 值賦變數,參考計數 +1 為 2
let c = a // 值賦變數,參考計數 +1 為 3

c = null // 值被覆寫,參考計數 -1 為 2
b = null // 值被覆寫,參考計數 -1 為 1
a = null // 值被覆寫,參考計數 -1 為 0 被垃圾回識訓制回收

回圈參考(參考計數的缺陷問題)

來看這樣一段代碼

function foo() {
    let a = { name: '小紅' }
    let b = { name: '小明' }
    a.name = b // b賦值給a物件中的name,b的參考次數為2
    b.name = a // a賦值給b物件中的name,a的參考次數為2
} // 說明:物件屬性值作為變數被賦值
foo()

程序決議:函式的變數物件在函式呼叫完成之后會將每個變數值設為null ,以便垃圾回識訓制進行回收,但在參考計數演算法的策略中,函式在呼叫后,回圈參考的變數ab依然保留了一次參考次數,也就是說,這兩個參考型別的參考次數為1,不會進行回收,

標記清除

基本原理:標志清除演算法把“物件不再需要”簡化定義為“物件是否可以獲得”,垃圾回收器將定期從根(全域物件)開始,找所有從根開始參考的物件,然后找這些物件參考的物件......直到最終垃圾回收器將找到所有可以獲取的物件和收集所有不能獲取的物件,其中不能獲取的物件則會被回收,


參考

MDN-閉包

我用了兩個月的時間才理解 let

JavaScript高級程式設計(第4版)

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/542449.html

標籤:JavaScript

上一篇:【Photoshop】切圖保存小坑(選擇png格式得到gif問題)

下一篇:雙十一銷量實時統計圖表

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more