1. 程式人生 > >Javascript和Java中閉包的理解

Javascript和Java中閉包的理解

一。Javascript中閉包:

1.變數的作用域

  要理解閉包,首先必須理解Javascript特殊的變數作用域。
  變數的作用域無非就是兩種:全域性變數和區域性變數。
  
  Javascript語言的特殊之處,就在於函式內部可以直接讀取全域性變數 
 var n=999;
 function f1(){
   alert(n);
 }
  f1(); // 999

  另一方面,在函式外部自然無法讀取函式內的區域性變數。 
 function f1(){
   var n=999;
 }
  alert(n); // error

  這裡有一個地方需要注意,函式內部宣告變數的時候,一定要使用var命令。如果不用的話,你實際上聲明瞭一個全域性變數! 
 function f1(){
   n=999;
 }
  f1();
  alert(n); // 999

2.如何從外部讀取區域性變數

  出於種種原因,我們有時候需要得到函式內的區域性變數。但是,前面已經說過了,正常情況下,這是辦不到的,只有通過變通方法才能實現。
  那就是在函式的內部,再定義一個函式。
  function f1(){
    n=999;
    function f2(){
      alert(n); // 999
    }
 }

  既然f2可以讀取f1中的區域性變數,那麼只要把f2作為返回值,我們不就可以在f1外部讀取它的內部變量了嗎!
  function f1(){
    n=999;
    function f2(){
      alert(n);
   }
   return f2;
 }
 var result=f1();
 result(); // 999

3.閉包的概念

  上面的f2函式,就是閉包。閉包其實就是定義在一個函式內部的函式(因為是子函式所以能夠讀取所在父函式的內部變數)。
  在本質上,閉包就是將函式內部和函式外部連線起來的一座橋樑。

4.閉包的用途

  1.可以讀取函式內部的變數.
  2.讓這些變數(閉包引用的變數)的值始終保持在記憶體中。
  function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
 }
 var result=f1();
 result(); // 999
 nAdd();
 result(); // 1000
        在這段程式碼中,result實際上就是閉包f2函式。它一共運行了兩次,第一次的值是999,第二次的值是1000。這證明了,函式f1中的區域性變數n一直儲存在記憶體中,並沒有在f1呼叫後被自動清除。
        為什麼會這樣呢?原因就在於f1是f2的父函式,而f2被賦給了一個全域性變數,這導致f2始終在記憶體中,而f2的存在依賴於f1,因此f1也始終在記憶體中,不會在呼叫結束後,被垃圾回收機制(garbage collection)回收。
        這段程式碼中另一個值得注意的地方,就是“nAdd=function(){n+=1}”這一行,首先在nAdd前面沒有使用var關鍵字,因此 nAdd是一個全域性變數,而不是區域性變數。其次,nAdd的值是一個匿名函式(anonymous function),而這個

       匿名函式本身也是一個閉包,所以nAdd相當於是一個setter,可以在函式外部對函式內部的區域性變數進行操作。

5.使用閉包的注意點

  1.由於閉包會使得函式中的變數都被儲存在記憶體中,記憶體消耗很大,所以不能濫用閉包

  2.閉包會在父函式外部,改變父函式內部變數的值。

6.閉包的應用場景

  1、保護函式內的變數安全。以最開始的例子為例,函式a中i只有函式b才能訪問,而無法通過其他途徑訪問到,因此保護了i的安全性。
  2、在記憶體中維持一個變數。依然如前例,由於閉包,函式a中i的一直存在於記憶體中,因此每次執行c(),都會給i自加1。
 

二。Java中的閉包

1.java中閉包的定義

  定義:閉包能夠將一個方法作為一個變數去儲存,這個方法有能力去訪問所在類的自由變數。

  Java 語言本身還沒有正式支援閉包,但它卻允許模擬閉包(內部類+介面)。可以使用匿名的內部類來實現閉包。

  如何讓這個普通物件能夠訪問所在類的自由變數?內部類。內部類能夠訪問外部類的所有屬性及方法。

  隱藏具體實現是內部類的作用之一,如何保證隱藏具體實現的同時還能將閉包傳遞到外部使用?讓內部類實現通用介面,然後將內部類物件向上轉型為介面型別。

2.程式碼簡單實現:

  	public final static String name = "純牛奶";// 名稱


		private static int num = 16;// 數量


		public Milk() {
			System.out.println(name + ":16/每箱");
		}


		/**
		 * 閉包
		 * 
		 * @return 返回一個喝牛奶的動作
		 */
		public Active HaveMeals() {
			return new Active() {
				public void drink() {
					if (num == 0) {
						System.out.println("木有了,都被你丫喝完了.");
						return;
					}
					num--;
					System.out.println("喝掉一瓶牛奶");
				}
			};
		}


		/**
		 * 獲取剩餘數量
		 */
		public void currentNum() {
			System.out.println(name + "剩餘:" + num);
		}
	}


	/**
	 * 通用介面
	 */
	interface Active {
		void drink();
	}  
	
	//閉包的使用
	public class Person {   
		public static void main(String[] args) {  
			//買一箱牛奶  
			Milk m = new Milk(); 
			Active haveMeals = m.HaveMeals();
			//沒事喝一瓶  
			haveMeals.drink();  
			//有事喝一瓶  
			haveMeals.drink(); 
			//看看還剩多少?  
			m.currentNum();  
		}   
	}  

4.總結: 

   1.實際專案中沒怎麼用過閉包,因此不能對他的好壞進行評論。 
   2.建議合理的使用閉包,不完全不使用,也不能濫用。 
   3.特別注意:閉包會導致資源不被回收,如上例,在main方法中將m設為null,使用haveMeals繼續呼叫drink方法仍然會喝掉一瓶牛奶,說明Milk物件並沒有被釋放掉。

  
  

相關推薦

JavascriptJava理解

一。Javascript中閉包: 1.變數的作用域   要理解閉包,首先必須理解Javascript特殊的變數作用域。   變數的作用域無非就是兩種:全域性變數和區域性變數。      Javascript語言的特殊之處,就在於函式內部可以直接讀取全域性變數  var n=

java 運用 實現方法傳遞

寫了一個測試java閉包的例項,在事件監聽中用得比較多的設計模式!定義一個介面,通過介面來傳遞方法體/** * @author yaohw * */ public interface Action{ public void excute(Object arg);

JavaScript實現的私有屬性的getter()setter()方法

參數 strong prop nbsp body 利用 edi 獲取 展示 註意: 以下的輸出都在瀏覽器的控制臺中 <!DOCTYPE html> <html> <head> <meta charset="utf-8"&g

JavaScript理解

func web瀏覽器 並且 清晰 分享 數量 接下來 我們 回收 相信很多人都有看過關於閉包的文章,但是真正意義上的了解清楚的也不多,今天我們就來談談對閉包的理解。 閉包在JavaScript中一直是一個很重要的存在,閉包很重要但是又很難理解,起初我也是這樣認為,但只要真

JavaScript的使用各種繼承介紹

一、什麼是閉包?     (1)閉包的概念:a、閉包就是函式巢狀時,讓區域性變數變成自由變數的環境,是一種讓區域性變數進化的方式。                      b、定義在一個函式內部的函式。 &

js理解

構建 但是 水平 作用 undefined 可能 技術 自身 復制 閉包是一個比較抽象的概念,尤其是對js新手來說.書上的解釋實在是比較晦澀,對我來說也是一樣.   但是他也是js能力提升中無法繞過的一環,幾乎每次面試必問的問題,因為在回答的時候.你的答案的深度,對術語的理

[譯]Javascript的各種例子

目的 點擊 span 而且 一個 code pre 一件事 播放 本文翻譯youtube上的up主kudvenkat的javascript tutorial播放單 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU&

JAVAjarwar的區別是

服務器 直接 jar文件 tomcat服務 一起 是把 目的 相關 web 其實jar包和war包都可以看成壓縮文件,用解壓軟件都可以打開,jar包和war包所存在的原因是,為了項目的部署和發布,通常把項目打包,通常在打包部署的時候,會在裏面加上部署的相關信息。 這個打包實

javascript最簡單的簡紹

覆蓋 計數 在一起 com 想要 .com neu 內部 文章 javascript中閉包是什麽 JavaScript 變量可以是局部變量或全局變量。私有變量可以用到閉包。閉包就是將函數內部和函數外部連接起來的一座橋梁。 函數的閉包使用場景:比如我們想要一個函數來執行計數

JavaScript 原理

閉包 引用程式碼片段 //var i=1;//汙染全域性 function fun(){ var i=1; //函式內變數 ao釋放 console.log(i++); } fun();//1 fun();//1 //i=0; 全域性汙染之後變數 會被影響 fun();/

javascript 理解

閉包的含義:閉包就是能夠讀取其他函式內部變數的函式,一個函式內部的函式 閉包的用途: 讀取函式內部的變數;讓這些變數的值始終保持在記憶體中 閉包的弊端:由於閉包會使得函式中的變數都被儲存在記憶體中,記憶體消耗很大, 所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能

#Java乾貨分享:一篇文章讓你深入瞭解Java介面

很多新手程式設計師對於Java中兩個具創新性的特徵————包與介面不是非常清楚,所以我特意發了這篇文章來闡述什麼是包,什麼是介面。 包(package)是多個類的容器,它們用於保持類的名稱空間相互隔離。 如果有想學習java的程式設計師,可來我們的java學習扣qun:79979,2590免

JavaScript教程筆記(8)-函式IIFE

1 閉包 閉包(closure)是JavaScript語言的一大特色,也是一個難點。理解閉包,首先要理解變數作用域。 作用域有兩種:全域性作用域和函式作用域。函式內部可以訪問全域性變數。 var n = 999; function f() { console.log(

javascript理解2

閉包的形成需要兩個條件: 1.在函式內部建立新的函式; 2.新的函式在執行時,訪問了函式的變數物件; 總結一下閉包: 閉包是在函式被呼叫執行的時候才被確認建立的。 閉包的形成,與作用域鏈的訪問順序有直接關係。 只有內部函式訪問了上層作用域鏈中的變數物件時,才會

對Python理解

定義 Python閉包表現為:如果在一個內部函式裡,對在外部作用域(非全域性作用域)的變數進行引用,那麼內部函式就被認為是閉包(closure)。 def outer(a): b = 1 def inner(): # 內部函式in

JavaScript理解

什麼是閉包 普通函式中,函式內部可以直接讀取全域性變數,函式外部無法讀取函式內部的區域性變數。 而閉包能夠讀取其他函式內部變數的函式,由於在 Javascript 語言中,只有函式內部的子函式才能讀取區域性變數,因此可以把閉包簡單理解成 “定義在一個函式內部的函式”。所以

關於JavaScript的datejava的date差14小時問題

今天遇到一個問題,在java中獲取的時間傳到前臺頁面, 原時間是這樣的:2016-11-10 15:29:11, 傳到前臺來是這樣的:Thu Nov 10 15:29:11 CST 2016, 在js中用getDate(),結果是11,getHours(),結果是5,也就是

java繼承的理解,super關鍵字,方法的重寫過載以及注意事項理解

一、類的繼承理解 在java中類的繼承是指:在一個現有類的基礎之上去構建一個新的類,構建出來的新的類被稱為子類,現有類是父類,子類會自動擁有父類所有可繼承的屬性和方法。繼承類是現有類的更具體一些,繼承類可能只擁有一部分父類的屬性和方法。 如圖,這就表示了繼承類是父類的一種更具體形式

JavaAtomic的原理分析

原文地址:http://blog.csdn.net/zhangerqing/article/details/43057799 Atomic簡介 Atomic包是Java.util.concurrent下的另一個專門為執行緒安全設計的Java包,包含多個原子操作類。這個

javascript理解之onload事件遍歷獲取陣列元素

我們在學javascript的時候是否遇到過這樣的程式碼,例如我們要在onload事件裡迴圈遍歷一個數組,對遍歷到的陣列元素進行操作。需要用到this物件,如下程式碼所示: onload = fu