本文最主要講講JavaScript閉包和this綁定相關的個人小發現,鑑於這方面的基礎知識已經有不少很好的文章講過了,因此基本的就不講了,推薦看看酷殼上的理解Javascript的閉包和阮一峯的學習Javascript閉包(Closure),寫的都很是好。javascript
首先來說講阮一峯的文章中的兩道思考題。html
代碼片斷一java
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());
這段代碼最後輸出的是shell
The Window
緣由在同一片文章的評論中已經有人指出了數據結構
George Wing 說:閉包
上面本人說得不太正確。
this的指向是由它所在函數調用的上下文決定的,而不是由它所在函數定義的上下文決定的。函數
對於最後返回的這個匿名函數學習
function(){ return this.name; };
它是做爲一個獨立的函數返回的,它的調用域是在全局上,因此會輸出全局變量name。this
代碼片斷二spa
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上的文章中的例子來進一步說明。
代碼片斷三
function greeting(name) { var text = 'Hello ' + name; // local variable // 每次調用時,產生閉包,並返回內部函數對象給調用者 return function() { alert(text); } } var sayHello=greeting("Closure"); sayHello() // 經過閉包訪問到了局部變量text
這段代碼輸出
Hello Closure
看上去好像很好理解,接下來看代碼片斷四:
代碼片斷四
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。這樣的數據結構就構成了一個單向的鏈表,每一個引用都指向外層的上下文場景。
針對代碼片斷四,就是咱們以前講過的,this
保存是調用環境下的上下文內容,因此會輸出全局的text
。
本文想說明的是如下兩點:
this
對變量進行訪問時,函數會經過文法環境中的外部引用(指針),一級級地往上找(單向鏈表),直到找到(或者最終找不到)對應的變量。這個結構是在函數定義的時候就決定了的。this
對變量進行訪問時,和絕大多數語言不一樣,JavaScript的this
保存的是調用環境的上下文,也就是說this
中的內容是在調用的時候決定的,因此訪問到的是當前環境下的對應變量,並不會像前一種狀況同樣進行逐級查找。