摘要:說了半天,究竟什么是閉包呢閉包就是函數的局部變量集合,只是這些局部變量在函數返回后會繼續存在。彈出上面函數中的函數就是閉包,就是通過建立函數來訪問函數內部的局部變量。閉包會在父函數外部,改變父函數內部變量的值。
JavaScript的閉包
首先聲明,這是一篇面向小白的博客,不過也歡迎各位大牛批評指正,謝謝。
??其實關于閉包各個論壇社區里都有很多的文章來講它,畢竟閉包是JavaScript中一個特色,也正因為這個雨中不同的特色也讓閉包理解起來有一些吃力。筆者在這里不僅僅是想介紹閉包,也向列舉一些筆者所見過的一些閉包,如果有讀者還有一些比較經典的閉包例子,希望可以在評論區里留一下,謝謝。
說了半天,究竟什么是閉包呢?
閉包就是函數的局部變量集合,只是這些局部變量在函數返回后會繼續存在。
閉包就是就是函數的“堆棧”在函數返回后并不釋放,我們也可以理解為這些函數堆棧并不在棧上分配而是在堆上分配。
當在一個函數內定義另外一個函數就會產生閉包。
為了便于理解,我們可以簡單的將閉包理解為:
閉包:是指有權訪問另外一個函數作用域中的變量的函數。
JavaScript中的作用域JavaScript中是沒有塊級作用域的。不過關于塊級作用域我們在這里不做深入探究,筆者在http://segmentfault.com/a/1190000004092842M中有對塊級作用域較為詳細的解釋,不懂的讀者可以去看看。
變量的作用域無非就是兩種:全局變量和局部變量。
Javascript語言的特殊之處,就在于函數內部可以直接讀取全局變量。
var n=999; function f1(){ alert(n); } f1(); // 999
如上函數,f1可調用全局變量n
另一方面,在函數外部自然無法讀取函數內的局部變量。
function f1(){ var n=999; } alert(n); // error
這里有一個地方需要注意,函數內部聲明變量的時候,一定要使用var命令。如果不用的話,你實際上聲明了一個全局變量。
function f1(){ n=999; } f1(); alert(n); // 999閉包
1. 理解閉包
我們已經理解了什么是作用域,什么是塊級作用域,那又該如何去訪問函數內部的變量呢?
出于種種原因,我們有時候需要得到函數內的局部變量。但是,前面已經說過了,正常情況下,這是辦不到的,只有通過變通方法才能實現。
function f1(){ var n=999; function f2(){ alert(n); } return f2; } var result=f1(); result();// 彈出999
上面函數中的f2函數就是閉包,就是通過建立函數來訪問函數內部的局部變量。
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,可以在函數外部對函數內部的局部變量進行操作。
3. 閉包的注意點
1)由于閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。
2)閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。
4. 經典閉包小案例
如果你能理解下面全部的案例,那你的閉包就算是真正掌握了。
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());//The Window
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()());//My Object
function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n); } }; } var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//undefined,?,?,? var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,? var c = fun(0).fun(1); c.fun(2); c.fun(3);//undefined,?,?,?
//問:三行a,b,c的輸出分別是什么?
這是一道非常典型的JS閉包問題。其中嵌套了三層fun函數,搞清楚每層fun的函數是那個fun函數尤為重要。
//答案:
//a: undefined,0,0,0
//b: undefined,0,1,2
//c: undefined,0,1,1
都答對了么?如果都答對了恭喜你在js閉包問題當中幾乎沒什么可以難住你了。
Happy hacking!文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/49689.html
摘要:說了半天,究竟什么是閉包呢閉包就是函數的局部變量集合,只是這些局部變量在函數返回后會繼續存在。彈出上面函數中的函數就是閉包,就是通過建立函數來訪問函數內部的局部變量。閉包會在父函數外部,改變父函數內部變量的值。 JavaScript的閉包 首先聲明,這是一篇面向小白的博客,不過也歡迎各位大牛批評指正,謝謝。 ??其實關于閉包各個論壇社區里都有很多的文章來講它,畢竟閉包是JavaScri...
摘要:圖片中的作用域鏈,是全局執行環境中的作用域鏈。然后此活動對象被推入作用域鏈的最前端。在最后調用的時候,創建先構建作用域鏈,再創建執行環境,再創建執行環境的時候發現了一個變量標識符。 從圖書館翻過各種JS的書之后,對作用域/執行環境/閉包這些概念有了一個比較清晰的認識。 栗子說明一切 第一個栗子 來看一個來自ECMA-262的栗子: var x = 10; (function foo(...
摘要:事件循環了解知識點線程執行棧線程是單線程的語言可以單線程將理解為只有一條車道在車道里后面的車在等前面的車通過后才能通過即當前面的程序沒有執行后面的程序也不能執行執行棧執行棧像車道被執行的程序會放入執行棧里但它的執行的順序是后面進來的程序先執 事件循環 了解知識點 線程 執行棧 task queue web api macro task micro task 線程 javascrip...
摘要:實現閉包將匿名函數在普通函數中當做參數傳入,也可以被返回。如果將匿名函數返回給外界,匿名函數會保存所引用的變量,而外界則不能得到這些變量,這樣形成閉包這個概念可能會更清晰一些。 原文:http://my.oschina.net/melonol/blog/126694 匿名函數提到閉包就不得不想起匿名函數,也叫閉包函數(closures),貌似PHP閉包實現主要就是靠它。聲明一個匿名函數...
摘要:和深入理解在和深入理解這篇博客里筆者曾做過總結,我們知道試單線程的產物,兩個函數就是利用了插入代碼的方式實現了偽異步,和的原理實際上是一樣的。綜上所述,其實終歸是單線程產物。無論如何異步都不可能突破單線程這個障礙。 說明:??這是筆者平時積累的一些覺得比較有意思或是比較有難度的JavaScript題目理解和心得,會保持長期更新。 1.setTimeout和setInterval深入理解...
閱讀 2871·2021-10-14 09:43
閱讀 1657·2021-09-29 09:34
閱讀 1743·2021-07-28 00:16
閱讀 2963·2019-08-30 15:53
閱讀 2905·2019-08-30 13:59
閱讀 2961·2019-08-30 13:57
閱讀 1091·2019-08-26 13:38
閱讀 1893·2019-08-26 13:25