JavaScript閉包和this綁定

本文最主要講講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`中的內容是在調用的時候決定的,因此訪問到的是當前環境下的對應變量,並不會像前一種狀況同樣進行逐級查找。



相關文章
相關標籤/搜索