摘要:閉包里面保存的變量只有被方法引用了的變量這個例子里,閉包里只有并沒有。那最后來說說的問題閉包到底是什么閉包是一個作用域。鑒于在的調試窗口,是放在下面的那閉包這個作用域是個什么范圍被后代方法子方法,孫子方法。。。
首先給js的作用域這個話題打標簽:2,var, 全局變量,局部變量,函數,undefined, 作用域提升,賦值不會提升,ReferenceError, 同名覆蓋。
打完標簽之后,我們來說跟作用域有關的幾條鐵打的規則:
1: JS的作用域有2種:全局作用域,函數作用域。
把作用域想象成一個房間,而{}是房間的門。門上裝了一個貓眼,所以房間里面可以看清楚外面,但是外面卻看不見里面。 在JAVA或者C里面,大括號可能會出現的情況有兩種: 1: 一個function定義的時候 2: 一個塊定義(比如if,for, while)的時候. 所以此時的作用域有三種類型: 1: 全局作用域, 2: 函數作用域 3: 塊級作用域。
但是在JS里面,雖然{}出現的情況也有兩種,但是只有function的{}才起到柵欄的作用。
2: 聲明在全局作用域里的變量是全局變量,聲明在函數里面的變量是局部變量。
3: 怎么創造一個全局變量和局部變量?
創造全局變量的方法有兩種:
1: 在全局作用域內用var定義: var a; 2: 聲明一個變量,不帶var(無論是在全局,在函數里面還是在一個塊里面):b
創造局部變量的方法只有一種:
在函數體里面,帶var聲明一個變量: function func(){var b;}
3: 使用一個沒有聲明過的變量,會得到一個ReferenceError。無論什么情況下。
4: 不同作用域內,同名的變量,越小的作用域的變量會覆蓋越大的作用域的。
4: 作用域提升:變量在聲明之前就可以引用了!
這個不是和第三點矛盾了嗎?其實并沒有。它背后的真正原理是:并不是作用域被提升(我們前面說了,一個變量的作用域會被框在一對柵欄{}里面,一旦這個柵欄確定了,那這個作用域是不可能變化的),其實是變量的‘聲明’在其作用域里面被放到任何代碼之前(當然包括引用它的代碼之前)。看一段代碼:
var scope = "global"; function func(){ console.log(scope); //輸出‘undefined’,而不是‘global’ var scope = "local"; console.log(scope); //輸出‘local’ }
看到第一個console,可能以為會輸出‘global’, 因為通過貓眼可以看見外面的變量。但是,一旦我們進到一個函數體里面,遇到任何的變量的引用,首先要先在當前的房間里面找,只有在當前的房間里面找不到時,才到父層去找。那為什么是‘undefined呢?其實以上的代碼等價于:
var scope = "global"; function func(){ var scope; //變量的聲明會提升到最前面,但是賦值并不會,所以此刻scope的值還只是undefined. console.log(scope); //輸出‘undefined’,而不是‘global’ scope = "local"; //賦值在這里完成 console.log(scope); //輸出‘local’ }
============閉包的分割線===========
1: 什么是閉包?
我看過看多不同的書,對必包的定義都不一樣,而且就算是我知道了閉包的定義,對我真正理解它的工作原理還是沒有什么用。所以,我就不去糾結它到底是什么,我接下來只關注它是怎么工作的。
2: 什么時候會形成閉包?
以下內容非原創,這里只是我自己的一個學習筆記。我看了http://www.jianshu.com/p/7312...(在這里感謝作者),跟著文章里面的例子(代碼根據自己的喜好改了一些)走一遍:
1: When? 閉包出現的時刻?
function foo() { var a = 2; function baz() { console.log( a ); } return baz; } var fn = foo() fn();//2
在斷點的過程中,運行完第9行代碼的時候,調試窗口里并沒有出現任何閉包;直到我運行了第10行代碼,跳到第5行的時候(也就是baz這個方法被調用的時候),調試窗口出現了閉包(Closure)。并且可以看到說foo是closure, 它包含一個變量a,值為2。
結論1:雖然很多書上說閉包跟函數定義的時候的作用域有關,跟它執行時候的作用域無關,但是它在瀏覽器里面出現的時機卻是在執行的時候。
2 How? 閉包出現的條件?
function foo() { var a = 2; function baz(m) { console.log(m); } return baz; } var fn = foo() fn(20); //20
很多地方都說在方法里面定義方法就會形成閉包,但是在這里例子里面,我執行完第10行的代碼,調試窗口并沒有出現任何閉包。和例1的差別在于,baz沒有引用變量a.
結論2:一個方法,一定要引用其父層方法(非自己方法內部的變量)的變量才會形成閉包。
但是閉包的形成是不是一定要執行到引用了父層作用域變量的方法才出現呢?看下面一個例子:
3: 當父層方法里有不只一個方法
function foo() { var a = 10; var b = 30; function fn1() { return a; } function fn2() { return 20; } return fn2; } var fn = foo(); fn();
當我執行到17行然后跳進其方法體(第10行)的時候,調試窗口出現了Closure, 并且它有一個變量a,
值為10。其實這個例子說明了兩個事情:
結論3: 在執行一個定義在方法里面的方法時,即使它的方法體自己沒有引用父層變量,但是只要有任何兄弟方法引用了,那就會形成閉包。閉包里面保存的變量只有被方法引用了的變量(這個例子里,閉包里只有a,并沒有b)。
4: 當不是兄弟方法,而是子方法引用了父級變量,會發生什么情況呢?
function foo() { var a = 10; var b = 30; function fn1() { var c = 20; function fn2(){ return a; } return fn2; } return fn1; } var fn1 = foo(); var fn2 = fn1(); fn2();
fn1方法體內沒有引用任何的父層變量,但是它的子方法fn2引用了變量a。在調試的過程中,當執行到f1的時候(執行到第6行,這時候可以看到變量c都還是"undefined"),Closure就已經出現了,并不像之前那樣一定要等到執行fn2.最后看一個例子:
5: 當不是直系子方法,而是侄子方法引用了父級變量
function foo() { var a = 10; var b = 30; function fn1() { var c = 20; function fn2(){ return a; } return fn2; } function fn3(){ return 40; } return fn3; } var fn3 = foo(); fn3();
當執行到調用fn3的時候,Chosure出現了。所以閉包到底是在什么時候形成呢?在我們前面的結論里面有提到說方法執行的時候,但是經過后面的這幾個例子說明并不一定非得是執行的時候,而且JavaScript是基于詞法作用域的語言(變量的作用域在其定義的時候就已經確定了,不依賴于執行時的環境),所以我傾向于閉包(Closure)是在方法定義的時候就形成了的。那最后來說說What的問題:閉包到底是什么?
1: 閉包是一個作用域。(鑒于在Chrome的調試窗口,Closure是放在Scope下面的)
2: 那閉包這個作用域是個什么范圍:被后代方法(子方法,孫子方法。。。)所引用的變量所在的作用域(或者說這個變量所在的方法)。
3: 閉包里面有什么:只包含被后代方法所引用了的變量,并不包含這個變量的兄弟姐妹。
4: 上面的所有例子都只引用了變量,換成方法,也都是同樣的結果。
真的是最后一個例子了:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/83506.html
摘要:的變量作用域是基于其特有的作用域鏈的。需要注意的是,用創建的函數,其作用域指向全局作用域。所以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。 作用域 定義 在編程語言中,作用域控制著變量與參數的可見性及生命周期,它能減少名稱沖突,而且提供了自動內存管理 --javascript 語言精粹 我理解的是,一個變量、函數或者成員可以在代碼中訪問到的范圍。 js的變量作...
摘要:作用域分為詞法作用域和動態作用域。這樣就形成了一個鏈式的作用域。一般情況下,當函數執行完畢時,里面的變量會被自動銷毀。而能夠訪問到這個在的編譯階段就已經定型了詞法作用域。 什么是作用域?在當前運行環境下,可以訪問的變量或函數的范圍。作用域分為詞法作用域和動態作用域。詞法作用域是在js代碼編譯階段就確定下來的; 對應的,with和eval語句會產生動態作用域。 會產生新的作用域的情況: ...
摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內部,也就是說為其聲明的變量隱式的劫持了所在的塊級作用域。 作用域與閉包 如何用js創建10個button標簽,點擊每個按鈕時打印按鈕對應的序號? 看到上述問題,如果你能看出來這個問題實質上是考對作用域的理解,那么恭喜你,這篇文章你可以不用看了,說明你對作用域已經理解的很透徹了,但是如果你看不出來這是一道考作用域的題目,...
摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內部,也就是說為其聲明的變量隱式的劫持了所在的塊級作用域。 作用域與閉包 如何用js創建10個button標簽,點擊每個按鈕時打印按鈕對應的序號? 看到上述問題,如果你能看出來這個問題實質上是考對作用域的理解,那么恭喜你,這篇文章你可以不用看了,說明你對作用域已經理解的很透徹了,但是如果你看不出來這是一道考作用域的題目,...
摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內部,也就是說為其聲明的變量隱式的劫持了所在的塊級作用域。 作用域與閉包 如何用js創建10個button標簽,點擊每個按鈕時打印按鈕對應的序號? 看到上述問題,如果你能看出來這個問題實質上是考對作用域的理解,那么恭喜你,這篇文章你可以不用看了,說明你對作用域已經理解的很透徹了,但是如果你看不出來這是一道考作用域的題目,...
閱讀 2077·2021-11-16 11:45
閱讀 578·2021-11-04 16:12
閱讀 1379·2021-10-08 10:22
閱讀 858·2021-09-23 11:52
閱讀 4142·2021-09-22 15:47
閱讀 3521·2021-09-22 15:07
閱讀 492·2021-09-03 10:28
閱讀 1737·2021-09-02 15:21