javascript的閉包是什麼

青灯夜游
發布: 2021-11-24 13:40:04
原創
2159 人瀏覽過

在javascript中,當兩個函數彼此嵌套時,內部的函數就是閉包。閉包是指有權存取另一個函數作用域中的變數的函數,而創建閉包的最常見的方式就是在一個函數內創建另一個函數,透過另一個函數存取這個函數的局部變數。

javascript的閉包是什麼

本教學操作環境:windows7系統、javascript1.8.5版、Dell G3電腦。

一、閉包是什麼?

閉包(closure)就是能夠讀取其他函數內部變數的函數。在javascript中,只有函數內部的子函數才能讀取局部變量,所以閉包可以理解成 “定義在一個函數內部的函數”。在本質上,閉包是將函數內部和函數外部連接起來的橋樑。 (閉包的最典型的應用是實現回呼函數(callback) )。

二、JS中閉包的優缺點及特性

優點:

##    1 、保護函數內的變數安全 

    2、在記憶體中維持一個變數(用的太多就變成了缺點,佔記憶體) ; 

#    3、邏輯連續,當閉包作為另一個函數呼叫的參數時,避免你脫離當前邏輯而單獨編寫額外邏輯。 

    4、方便呼叫情境的局部變數。 

    5、加強封裝性,可達到變數的保護效果。

缺點:

    1、常駐內存,會增加記憶體使用量,使用不當很容易造成記憶體外洩。

    2、還有有一個非常嚴重的問題,那就是內存浪費問題,這個內存浪費不僅僅因為它常駐內存,更重要的是,對閉包的使用不當會造成無效內存的產生。

特性:

    1、函數巢狀函數 

#    1、函數巢狀函數 

    2、內部函數可以存取外部函數的變數 

#    3、參數和變數不會被回收。

三、變數作用域

要理解閉包,只理解上邊關於閉包的概念是不行的。首先要理解javascript的特殊的變數作用域。 

1、變數的作用域無非就兩種:全域變數與局部變數。 

2、javascript語言的特別之處就在於:函數內部可以直接讀取全域變量,但是在函數外部無法讀取函數內部的局部變數。 

3、注意點:在函數內部宣告變數的時候,一定要使用var指令。如果不用的話,你實際上聲明的是一個全域變數!

四、用程式碼詮釋閉包

  在Javascript中閉包的創建過程,如以下程式所示。

function a () {
   var i = 0;
   function b () {
      alert (i++);
   }
  return b;
}
var c = a();
c();  //函数调用
登入後複製
程式碼特點

這段程式碼有兩個特點: 

      1、函數b嵌套在函數a內部; 

      2、函數a返回函數b。

這樣在執行完var c = a( )後,變數c其實是指向了函數b,再執行c( )後就會彈出一個視窗顯示i的值(第一次為1) 。這段程式碼其實就創建了一個閉包,這是因為函數a外的變數c引用了函數a內的函數b。也就是說,當函數a的內部函數b被函數a外的一個變數引用的時候,就建立了一個閉包。

作用

簡而言之,閉包的作用就是在a執行完並返​​回後,閉包使得Javascript的垃圾回收機制不會收回a所佔用的資源,因為a的內部函數b的執行需要依賴a中的變數。

在上面的例子中,由於閉包的存在使得函數a返回後,a中的i始終存在,這樣每次執行c(),i都是自加1後alert出i的值。 

那我們來想像另一個情況,如果a回傳的不是函數b,情況就完全不同了。因為a執行完後,b沒有被回傳給a的外界,只是被a所引用,而此時a也只會被b引用,因此函數a和b互相引用但又不被外界打擾(被外界引用) ,函數a和b就會被回收。

應用場景

1、保護函數內的變數安全性。函數a中i只有函數b才能訪問,而無法透過其他途徑訪問到,因此保護了i的安全性。 

2、在記憶體中維持一個變數。由於閉包,函數a中i的一直存在於記憶體中,因此每次執行c(),都會給i自加1。 ###

五、如何从外部读取函数内部的局部变量?

  出于种种原因,我们有时候需要获取到函数内部的局部变量。但是,上面(三、变量作用域)已经说过了,正常情况下,这是办不到的!只有通过变通的方法才能实现。那就是在函数内部,再定义一个函数。

function demo1 () {
    var n = 6699;
    function demo2 () {
      alert(n); // 6699
    }
  }
登入後複製

在上面的代码中,函数 demo2 就被包括在函数demo1内部,这时demo1内部的所有局部变量,对demo2都是可见的。但是反过来就不行,demo2内部的局部变量,对demo1就是不可见的。 

这就是Javascript语言特有的”链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。 

既然demo2可以读取demo1中的局部变量,那么只要把demo2作为返回值,我们不就可以在demo1外部读取它的内部变量了吗!

六、闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中,不会在demo1调用后被自动清除。 

那为什么会这样呢?原因就在于demo1是demo2的父函数,而demo2被赋给了一个全局变量,这导致demo2始终在内存中,而demo2的存在依赖于demo1,因此demo1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

七、使用闭包的注意点

1、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。 

2、闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

八、总结:

1、闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。 

2、不适合场景:返回闭包的函数是个非常大的函数。 

    闭包的典型框架应该就是jquery了。 

    闭包是javascript语言的一大特点,主要应用闭包场合主要是为了:设计私有的方法和变量。 

    这在做框架的时候体现更明显,有些方法和属性只是运算逻辑过程中的使用的,不想让外部修改这些属性,因此就可以设计一个闭包来只提供方法获取。 

3、 不必纠结到底怎样才算闭包,其实你写的每一个函数都算作闭包,即使是全局函数,你访问函数外部的全局变量时,就是闭包
的体现。

更多编程相关知识,请访问:编程入门!!

以上是javascript的閉包是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!