搜尋
首頁web前端js教程一起認識閉包

一起認識閉包

Sep 08, 2020 pm 01:25 PM
閉包

一起認識閉包

相關學習推薦:javascript影片教學

前言

閉包 永遠都是前端開發者繞不過去的一個坎,不管你喜歡與否,在工作和麵試中,都會遇到。每個人對閉包的理解都不盡相同,這裡筆者談談自身對閉包的理解。 (如果與您的理解有出入,請以自己為準  )

如何定義閉包

在給定義之前,不妨看看別人是如何定義閉包的:

函數物件可以透過作用域鏈相互關聯起來,函數體內部的變數都可以保存在函數作用域內,這種特性在電腦科學文獻中稱為「閉包」 -- JavaScript權威指南(第六版)

閉包是指有權存取另一個函數作用域中的變數的函數。建立閉包的常見方式,就是在一個函數內部建立另一個函數。 -- JavaScript高階程式設計(第三版)

當函數可以記住並存取所在的詞法作用域時,就產生了閉包,即使函數是在當前詞法作用域之外執行。 -- 你不知道的JavaScript(上卷)

雖然上面的幾段話描述起來並不一樣,但是您細細品味後還是能找出一些共同點。其中最重要的是不同作用域之間的聯繫。當然了,您可以直接引用上面的定義(畢竟上面幾個定義還是比較權威的),這裡筆者比較喜歡最後一段的定義,同時力推《你不知道的JavaScript(上卷)》這本書,值得反覆細讀。

閉包涉及哪些知識點

光給出定義是遠遠不夠的,還必須探討內部涉及了哪些知識點。下面是筆者認為有用到的知識點。

作用域與作用域鏈

嗯,其實筆者知道你們都想到了這點(不會吧,不會有人沒想到這點吧)。既然大家都了解作用域。這裡就簡單描述一下,過一下場即可。

作用域:根據名稱找出變數的一套規則。分為三種類型:全域作用域;函數作用域;區塊作用域。

要注意的是區塊作用域,ES6新增的規格。在花括號{}裡面使用let,const定義的變量,都會綁定到該作用範圍內,花括號以外的地方無法存取。 注意:在花括號開始 到 let變數宣告之前,存在暫時性死區(該點不在本文討論範圍)。

作用域鏈:當不同的作用域 (混~困惑~在~一~起~ 呸,不小心齣戲了) 圈套在一起時,就形成了作用域鏈。注意的是,查找方向是從內到外的。

為什麼作用域的找出方向是從內到外的呢?這是個很有趣的問題。個人覺得是跟js執行函數的入棧方式決定的(感覺有點偏題了,有興趣的小夥伴可以去查一下資料)。

詞法作用域

函數之所以可以存取另一個函數作用域的變數(或記住目前的作用域並在目前以外的地方存取)的關鍵點就是詞法作用域在運作。這一點很重要,但不是所有人都知道這個知識點,這裡簡單探討一下。

在程式設計界中,存在著兩種作用域工作模式,一種是被大多數程式語言所採用的詞法作用域;另一種就是與其相反的動態作用域(這個不在本文的討論範圍)。

詞法作用域: 變數和區塊的作用域在您編寫程式碼的階段就已經確定好了,不會隨著呼叫的物件或地方的不同而改變(感覺跟this相反)。

要不,舉個栗子看看吧:

let a = 1;
function fn(){
    let a = 2;
    function fn2(){
        console.log(a);
    }
 return fn2;
}

let fn3 = fn();
fn3();

從上面的定義可以知道,fn是一個閉包函數,fn3 拿到了fn2的指標位址,當fn3執行的時候,其實是執行fn2,而裡面的a變量,根據作用域鏈的查找規則,找到的是fn作用域內的變數a,所以最終的輸出是2,而不是1。 (可以看下圖)

一起認識閉包

題外話,如何欺騙詞法作用域?

雖然詞法作用域是靜態的,但還是有辦法可以欺騙它,達到動態的效果。

第一种方法是使用eval. eval可以把字符串解析成一个脚本来运行,由于在词法分析阶段,无法预测eval运行的脚本,所以不会对其进行优化分析。

第二种方法是with. with通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。with本身比较难掌握,使用不当容易出现意外情况(如下例子),不推荐使用 -.-

function Fn(obj){
    with(obj){
        a = 2;
    }
}

var o1 = {
    a:1
}
var o2 = {
    b:1
}

Fn(o1);
console.log(o1.a); //2
Fn(o2);
console.log(o2.a); //undefined;
console.log(a); //2 a被泄漏到全局里面去了
// 这是with的一个副作用, 如果当前词法作用域没有该属性,会在全局创建一个

闭包能干啥?

闭包的使用场景可多了,平时使用的插件或者框架,基本上都有闭包的身影,可能您没留意过罢了。下面笔者列举一些比较常见的场景。

  1. 模拟私有变量和方法,进一步来说可以是模拟模块化;目前常用的AMD,CommonJS等模块规范,都是利用闭包的思想;

  2. 柯里化函数或者偏函数;利用闭包可以把参数分成多次传参。如下面代码:

// 柯里化函数
function currying(fn){
    var allArgs = [];

    function bindCurry(){
        var args = [].slice.call(arguments);
        allArgs = allArgs.concat(args);
        return bindCurry;
    }
    bindCurry.toString = function(){
        return fn.apply(null, allArgs);
    };

    return bindCurry;
}
  1. 实现防抖或者节流函数;

  2. 实现缓存结果(记忆化)的辅助函数:

// 该方法适合缓存结果不易改变的函数
const memorize = fn => {
    let memorized = false;
    let result = undefined;
    return (...args) => {
        if (memorized) {
            return result;
        } else {
            result = fn.apply(null,args); 
            memorized = true;
            fn = undefined;
            return result;
        }
    };
};

如何区分闭包?

说了那么多,我怎么知道自己写的代码是不是闭包呢?先不说新手,有些代码的确隐藏的深,老鸟不仔细看也可能发现不了。 那有没有方法可以帮助我们区分一个函数是不是闭包呢?答案是肯定的,要学会善于利用周边的工具资源,比如浏览器。

打开常用的浏览器(chrome或者其他),在要验证的代码中打上debugger断点,然后看控制台,在scope里面的Closure(闭包)里面是否有该函数(如下图)。

一起認識閉包

闭包真的会导致内存泄漏?

答案是有可能。内存泄漏的原因在于垃圾回收(GC)无法释放变量的内存,导致运行一段时候后,可用内存越来越少,最终出现内存泄漏的情况。常见的内存泄漏场景有4种:全局变量;闭包引用;DOM事件绑定;不合理使用缓存。其中,闭包导致内存泄漏都是比较隐蔽的,用肉眼查看代码判断是比较难,我们可用借助chrome浏览器的Memory标签栏工具来调试。由于篇幅问题,不展开说明了,有兴趣自己去了解一下如何使用。

想了解更多编程学习,敬请关注php培训栏目!

以上是一起認識閉包的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:juejin。如有侵權,請聯絡admin@php.cn刪除
JavaScript:探索網絡語言的多功能性JavaScript:探索網絡語言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的演變:當前的趨勢和未來前景JavaScript的演變:當前的趨勢和未來前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

神秘的JavaScript:它的作用以及為什麼重要神秘的JavaScript:它的作用以及為什麼重要Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python還是JavaScript更好?Python還是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。1.Python以简洁语法和丰富库生态著称,适用于数据分析和Web开发。2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

如何安裝JavaScript?如何安裝JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安裝,因為它已內置於現代瀏覽器中。你只需文本編輯器和瀏覽器即可開始使用。 1)在瀏覽器環境中,通過標籤嵌入HTML文件中運行。 2)在Node.js環境中,下載並安裝Node.js後,通過命令行運行JavaScript文件。

在Quartz中如何在任務開始前發送通知?在Quartz中如何在任務開始前發送通知?Apr 04, 2025 pm 09:24 PM

如何在Quartz中提前發送任務通知在使用Quartz定時器進行任務調度時,任務的執行時間是由cron表達式設定的。現�...

在JavaScript中,如何在構造函數中獲取原型鏈上函數的參數?在JavaScript中,如何在構造函數中獲取原型鏈上函數的參數?Apr 04, 2025 pm 09:21 PM

在JavaScript中如何獲取原型鏈上函數的參數在JavaScript編程中,理解和操作原型鏈上的函數參數是常見且重要的任�...

微信小程序webview中Vue.js動態style位移失效是什麼原因?微信小程序webview中Vue.js動態style位移失效是什麼原因?Apr 04, 2025 pm 09:18 PM

在微信小程序web-view中使用Vue.js動態style位移失效的原因分析在使用Vue.js...

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中