本文最主要講講JavaScript閉包和this綁定相關的個人小發現,鑑於這方面的基礎知識已經有不少很好的文章講過了,因此基本的就不講了,推薦看看[酷殼](http://coolshell.cn/)上的[理解Javascript的閉包](http://coolshell.cn/articles/6731.html)和[阮一峯](http://www.ruanyifeng.com/blog/)的[學習Javascript閉包(Closure)](http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html),寫的都很是好。 首先來說講阮一峯的文章中的兩道思考題。 **代碼片斷一** ```js var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()()); ``` 這段代碼最後輸出的是 ``` The Window ``` 緣由在同一片文章的評論中已經有人指出了 > George Wing 說: > > 上面本人說得不太正確。 this的指向是由它所在函數調用的上下文決定的,而不是由它所在函數定義的上下文決定的。 對於最後返回的這個匿名函數 ```js function(){ return this.name; }; ``` 它是做爲一個獨立的函數返回的,它的調用域是在全局上,因此會輸出全局變量name。 **代碼片斷二** ```js var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()()); ``` 代碼片斷二最後輸出的是 ``` My Object ``` 這裏就要考慮`var that = this;`這句的做用了,因爲`getNameFunc`是`object`內部的函數,因此它調用的上下文`this`保存的是`object`的信息,將其保存到`that`變量,這樣做爲內部函數的匿名函數就能夠直接訪問了。 能夠注意到的是,阮一峯文章中的代碼,都是將經過一個JSON對象來訪問內部的函數,這樣其實有些地方還不夠清晰,畢竟不怎麼嚴格地說,閉包就是函數內部的函數,因此我借用CoolShell上的文章中的例子來進一步說明。 **代碼片斷三** ```js function greeting(name) { var text = 'Hello ' + name; // local variable // 每次調用時,產生閉包,並返回內部函數對象給調用者 return function() { alert(text); } } var sayHello=greeting("Closure"); sayHello() // 經過閉包訪問到了局部變量text ``` 這段代碼輸出 ``` Hello Closure ``` 看上去好像很好理解,接下來看代碼片斷四: **代碼片斷四** ```js var text = 'findingsea'; function greeting(name) { var text = 'Hello ' + name; // local variable // 每次調用時,產生閉包,並返回內部函數對象給調用者 return function() { alert(this.text); } } var sayHello=greeting("Closure"); sayHello() // 經過閉包訪問到了局部變量text ``` 這段代碼輸出 ``` findingsea ``` 這是爲何呢? 針對代碼片斷三,CoolShell上的原文有解釋: >文法環境中用於解析函數執行過程使用到的變量標識符。咱們能夠將文法環境想象成一個對象,該對象包含了兩個重要組件,環境記錄(Enviroment Recode),和外部引用(指針)。環境記錄包含包含了函數內部聲明的局部變量和參數變量,外部引用指向了外部函數對象的上下文執行場景。全局的上下文場景中此引用值爲NULL。這樣的數據結構就構成了一個單向的鏈表,每一個引用都指向外層的上下文場景。 ![closure](http://findingsea-blog-images.qiniudn.com/closure.png) 針對代碼片斷四,就是咱們以前講過的,`this`保存是調用環境下的上下文內容,因此會輸出全局的`text`。 ####總結 本文想說明的是如下兩點: 1. 在函數閉包中,不使用`this`對變量進行訪問時,函數會經過文法環境中的外部引用(指針),一級級地往上找(單向鏈表),直到找到(或者最終找不到)對應的變量。這個結構是在函數定義的時候就決定了的。 2. 在函數閉包中,使用`this`對變量進行訪問時,和絕大多數語言不一樣,JavaScript的`this`保存的是調用環境的上下文,也就是說`this`中的內容是在調用的時候決定的,因此訪問到的是當前環境下的對應變量,並不會像前一種狀況同樣進行逐級查找。