其實js支援函數閉包的主要原因是因為js需要函數能夠保存資料。這裡的保存資料是只函數在運行結束以後函數內變數的值也會進行保存。至於為什麼js需要在函數內可以保存數據,那就是js是一種函數式語言。在函數內保存資料是函數式語言的一大特徵。
回顧前面介紹過的三種定義函數方式
functiosu(numnumreturnunum//函數宣告語法定義
vasufunction(numnum)returnunum}//函數表達式定義
vasuneFunction("num""num""returnunum")//Functio建構子
在分析閉包之前我們先來看看,定義和呼叫函數容易犯的錯誤。
例1:
sayHi(); //错误:函数还不存在 var sayHi = function () { alert("test"); };
例2:
if (true) { function sayHi() { alert("1"); } } else { function sayHi() { alert("2"); } } sayHi();//打印结果并不是我们想要的
例3:
var fun1 = function fun2() { alert("test"); } fun2();//错误:函数还不存在
在範例1中,我們不能在使用函數宣告式語法定義之前呼叫函數。解決方案:
1.如果使用函數表達式定義函數的話,需要在表達式定義後呼叫。
var sayHi = function () { alert("test"); }; sayHi()
2.使用函數宣告式。 (這裡瀏覽器引擎會 函數宣告提升, 在所有程式碼執行前先讀取函數宣告)
sayHi(); function sayHi () { alert("test"); };
在例2中,我們預期的結果應該是列印1,實際結果是列印2。
if (true) { function sayHi() { alert("1"); } } else { function sayHi() { alert("2"); } } sayHi();//打印结果并不是我们想要的
為什麼會這樣?正因為 函數宣告提升 ,所以瀏覽器在預解析的時候不會判斷if條件,直接解析第二個函數定義的時候覆蓋了第一個。
解決方案:
var sayHi; if (true) { sayHi = function () { alert("1"); } } else { sayHi = function () { alert("2"); } } sayHi();
在例3中,發現只能只用fun1()調用,而不能使用fun2()調用。
我自己的理解,真正原因不知道。沒找到資料。
因為1: function fun3() { }; 等效與 var fun3 = function fun3() { }; 如圖:
所以只能只用fun1()調用,不能使用fun2()調用。
其實這裡我還是有疑問的?哪位大神知道,望告知。
既然,fun2在外面不能呼叫為什麼在函數內部能呼叫?雖然在debugger還是得不到fun1。
好了,透過上面的三題目熱身。我們繼續今天的主題「閉包」。
1.什麼是閉包?
定義:就是有權存取另一個函數作用域的變數的函數
我們先從一個範例函數開始:
例1:
function fun() { var a = "张三"; } fun();//在我们执行完后,变量a就被标记为销毁了
例2:
function fun() { var a = "张三"; return function () { alert("test"); } } var f = fun();//同样,在我们执行完后,变量a就被标记为销毁了
例3:
function fun() { var a = "张三"; return function () { alert(a); } } var f = fun();//【现在情况发生变化了,如果a被销毁,显然f被调用的话就不能访问到变量a的值了】 f();//【然后变量a的值正常的被访问到了】 //这就是闭包,当函数A 返回的函数B 里面使用到了函数A的变量,那么函数B就使用了闭包。 示例: function fun() { var a = "张三"; return function () { alert(a); } } var f = fun();//【现在情况发生变化了,如果a被销毁,显然f被调用的话就不能访问到变量a的值了】 f();//【然后变量a的值正常的被访问到了】
顯然,濫用閉包會增加記憶體的使用。所以非特殊情況盡量不要使用閉包。如果用到了,記得手動設定空引用,記憶體才能被回收 f = null ;
圖解:(不了解作用域鏈的同學請先看前面的文章 作用域與作用域鏈 )
2.什麼是匿名函數? (只是解釋這個概念)
如:(即,沒有名字的函數)
關於物件中函數的回傳值是匿名函數時,this的怪異現象
講解之前,先清醒下頭腦,不要越看越迷糊了。如果迷糊了,那就直接忽略下面的。
var name1 = "张三"; var obj = { name1: "李四", fun2: function () { alert(this.name1); }, fun3: function () { return function () { alert(this.name1); } } }
obj.fun2();//列印結果"李四"意料之中的。
obj.fun3()();//因為這裡回傳的是一個函數,所以要再加一對()來呼叫。列印結果是"張三",意料之外。
//真是百事不得其解啊,什麼this指向了全局?
我們前面講過“ 哪個物件點出來的方法,this就是哪個物件 ”,那我們的 obj.fun3()() 列印的是“張三”也就是說this執行了全域作用域。
我們看看下面的範例也許就知道為什麼了。
var name1 = "张三"; var obj = { name1: "李四", fun2: function () { alert(this.name1); }, fun3: function () { return function () { alert(this.name1); } } } //obj.fun3()(); var obj2 = {}; obj2.name1 = "test"; obj2.fun = obj.fun3(); obj2.fun();//打印结果"test",再次证明了“哪个对象点出来的方法,this就是哪个对象”. var name1 = "张三"; var obj = { name1: "李四", fun2: function () { alert(this.name1); }, fun3: function () { return function () { alert(this.name1); } } } //obj.fun3()(); var obj2 = {}; obj2.name1 = "test"; obj2.fun = obj.fun3(); obj2.fun();//打印结果"test",再次证明了“哪个对象点出来的方法,this就是哪个对象”.
我們來分解下 obj.fun3()() 先是 obj.fun3() 回傳一個匿名函數到了window作用域,然後接著呼叫this就指向了window了。 ( 感覺解釋有點勉強,也不知道對不,暫時自己先是這麼理解的 )
閉包形成的原因:記憶體釋放問題
一般,當函數執行完畢後,局部活動物件會被銷毀,記憶體中僅保存全域作用域,但閉包的情況是不一樣的。
閉包的活動物件依然會保存在記憶體中,於是像上例中,函數呼叫返回後,變數i是屬於活動物件裡面的,就是說其棧區還沒釋放,但你呼叫c()的時候i變數保存的作用域鏈從b()->a()->全域去尋找作用域var i宣告所在,然後找到了var i=1;然後在閉包內++i;結果,最後輸出的值就是2了;
以上所述是小編給大家分享的JavaScript基礎篇(6)之函數表達式閉包,希望大家喜歡。

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

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

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

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

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

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