JavaScript閉包-閉包中的變數與this對象
在JavaScript中作用域鏈的機制會引發一些副作用:閉包只能夠取得包含函數中任何變數的最後一個值。在使用閉包的時候,我們一定要注意變數值的問題,因為這是經常出錯的地方。
下面我們以一個非常極端的例子來說明這個問題,在實際開發中我們一般不會這樣寫程式碼。這個範例的程式碼如下:
function fn1(){ var arr = new Array(); //变量i保存在fn1作用域中 for(var i = 0; i < 10;i++){ arr[i] = function(){ return i; } } return arr; } var values = fn1(); for(var i = 0; i < values.length;i++){ //此时通过闭包来调用所有的函数,当输出i的时候会到上一级的作用域中查找,此时i的值是10,所以输出的都是10 document.write(values[i]()+"<br>"); }
執行上面的程式碼,我們預期會在頁面中列印出0-9,但是實際上會列印10個10。讓我們來分析這段程式碼:實現程式碼中創建了一個函數fn1,在函數中創建了一個數組對象,並透過一個for循環為數組賦值,循環了10次,每一次往數組中填充一個匿名函數返回值,最後傳回數組物件。接著取得fn1函數的引用,然後透過循環在頁面中輸出數組中的值。
上面的程式的作用域鏈記憶體模型如下圖所示:
從圖中我們可以看到,每次在fn1函數中的循環都會產生一個匿名函數,它們有各自的作用域鏈,它們的作用域鏈的高位都指向全域作用域,中間位指向外層的fn1作用域,低位才是指向自己的作用域。
當函數fn1執行完成之後,fn1作用域中的屬性i的值為10,此時GC開始回收fn1,但它發現有匿名函數指向fn1的作用域,所以fn1的作用域不會被回收。
在匿名函數執行的時候,它在自己的空間中查找屬性i,但是沒有找到,於是就到它上級的fn1作用域中去查找,此時,fn1作用域中的i值為10,所以所以匿名函數都會得到相同的i值:10。
解決這個問題的方法是在匿名函數中再傳回一個匿名函數,並且透過一個變數來保存目前的數值。程式碼如下:
function fn1(){ var arr = new Array(); for(var i = 0; i < 10;i++){ arr[i] = function(num){ return function(){ return num; } }(i); } return arr; } var values = fn1(); for(var i = 0; i < values.length;i++){ //每一个fs都是在不同的作用域链中,num也是保存在不同的作用域中,所以输出0-9 document.write(values[i]()+"<br>"); }
此時,num的值保存在每個匿名函數自己的作用域中,數值剛好等於每次迴圈的索引值。這樣,在每次呼叫匿名函數的時候,它會在自己的空間中找到num屬性,而這些num的值都是不同的,同時也不會再到fn1函數作用域中去尋找i屬性。
上面的程式碼會產生20個匿名函數的作用域,如果程式碼中不是簡單的回傳值,而是一些更複雜的操作,將會佔用大量的記憶體空間。
閉包中的this物件
在閉包中使用this物件也會出現一些意想不到的問題。 this物件是在執行時期基於函數的執行環境綁定的:對於全域函數,this物件就是window,而當函數在作為某個物件的方法被呼叫時,this就是那個物件。在匿名函數中,this物件通常是指向window的。我們來看下面的例子:
var name = "window"; var person = { name : "Leon", age:22, say:function(){ return function(){ return this.name; } } } console.info(person.say()()); //控制台输出:window
上面的程式碼中,我們呼叫person物件的say()方法時,印出來的不是person物件的名字,而是全域的名字「window」。當完成person.say()之後,函數調用完畢,在該函數呼叫結束之前,this是在指向person的,但是在調用匿名函數的時候,this就指向window了,所以得到的結果是“window” 。
解決這個問題的方法是在say()方法中將this引用賦值給一個臨時變數。程式碼如下:
var name = "window"; var person = { name : "Leon", age:22, say:function(){ var that = this; return function(){ return that.name; } } } console.info(person.say()()); //控制台输出:Leon
以上就是JavaScript閉包-閉包中的變數和this物件的內容,更多相關內容請關注PHP中文網(www.php.cn)!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

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

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

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

Dreamweaver CS6
視覺化網頁開發工具

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

熱門話題

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

Java中的實例變數是指定義在類別中,而不是方法或建構子中的變數。實例變數也稱為成員變量,每個類別的實例都有自己的一份實例變數副本。實例變數在創建物件的過程中被初始化,以及在物件的生命週期中保存並保持其狀態。實例變數的定義通常放在類別的頂部,可以用任何存取修飾符來聲明,可以是public、private、protected或預設存取修飾符。這取決於我們希望這個變

使用Ajax從PHP方法取得變數是Web開發中常見的場景,透過Ajax可以實作頁面無需刷新即可動態取得資料。在本文中,將介紹如何使用Ajax從PHP方法中取得變量,並提供具體的程式碼範例。首先,我們需要寫一個PHP檔案來處理Ajax請求,並傳回所需的變數。下面是一個簡單的PHP檔案getData.php的範例程式碼:

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

python憑藉其簡單易讀的語法,廣泛應用於廣泛的領域。掌握Python語法的基礎架構至關重要,既可以提高程式效率,又能深入理解程式碼的運作方式。為此,本文提供了一個全面的心智圖,詳細闡述了Python語法的各個面向。變數和資料類型變數是Python中用於儲存資料的容器。心智圖展示了常見的Python資料類型,包括整數、浮點數、字串、布林值和列表。每個資料類型都有其自身的特性和操作方法。運算符運算符用於對資料類型執行各種操作。心智圖涵蓋了Python中的不同運算子類型,例如算術運算子、比

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

C中const的詳解及程式碼範例在C語言中,const關鍵字用來定義常數,表示該變數的值在程式執行過程中不能被修改。 const關鍵字可以用來修飾變數、函數參數、函數傳回值。本文將對C語言中const關鍵字的使用進行詳細解析,並提供具體的程式碼範例。 const修飾變數當const用來修飾變數時,表示變數為唯讀變量,一旦賦值就無法再修改。例如:constint
