首頁 web前端 js教程 JavaScript閉包-閉包中的變數與this對象

JavaScript閉包-閉包中的變數與this對象

Jan 20, 2017 pm 02:19 PM

在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函數的引用,然後透過循環在頁面中輸出數組中的值。

上面的程式的作用域鏈記憶體模型如下圖所示:

JavaScript閉包-閉包中的變數與this對象

從圖中我們可以看到,每次在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)!


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱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 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

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

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

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

什麼是Java中的實例變數 什麼是Java中的實例變數 Feb 19, 2024 pm 07:55 PM

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

如何使用Ajax從PHP方法取得變數? 如何使用Ajax從PHP方法取得變數? Mar 09, 2024 pm 05:36 PM

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

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

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

Python 語法的心智圖:深入理解程式碼結構 Python 語法的心智圖:深入理解程式碼結構 Feb 21, 2024 am 09:00 AM

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

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

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

深入理解C語言中的const 深入理解C語言中的const Feb 18, 2024 pm 12:56 PM

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

See all articles