今天在群里面瞎談,就談到“閉包”上來了,何種語言支持閉包?自己g下吧,其中JavaScript是支持閉包概念的一種語言/腳本(?)。以下是我對他的見解(以javascript舉例)。
先了解下在一個對象內如何聲明變量,一下以Test對象為例:
Public變量:
function Test()
{
this.x = 1;
}
或者
Test.prototype.x = 1;
公共變量簡而言之,外界對象可以對公共變量訪問,并且公共變量可以在對象的構造函數中聲明外,還可以在對象的prototype成員中聲明。換句話說,你可以在任何時候添加公共變量(利用prototype)。prototype是一個特別的成員變量,js就是利用這個成員變量的特性來實現繼承的。當一個成員被檢索且沒有在對象中發現的時候,那么它就會從對象構造器的prototype成員中獲取他。如果要從外界調用這個對象的方法,或者是通過這個方法操作這個對象里面的所有成員,你可以通過prototype加入:
Test.prototype.Plus = function () {
}
Private變量:
function Test()
{
var self = this;
var x = 1;
function Plus1() {
}
var pPlus = function Plus2() {
}
}
私有的變量只能由成員的私有方法或者是特權方法(Privileged,下面講到)訪問,需要注意的是,上面的Plus1()這個方法和pPlus()這個方法是一樣的,只是聲明的方式不通而已,他們都是私有方法,他和特權變量的聲明方法很相似,只是少了個this多了個var,但是他們是不同的,應該特別注意。另外一點是,私有變量是在無法被外界訪問的同時,他也不能由對象的公共方法訪問。私有方法只是在構造函數內的內部方法。私有變量只能在構造函數中聲明。
Privileged變量:
function Test()
{
this.pPlus = function () {
}
}
什么叫Privileged(特權)變量呢?特權方法可以訪問私有方法和私有變量,同時他對外界是可見的。你可以重新聲明這個私有方法或者是刪除他(重新對這個特權方法賦值,null值表示刪除),但是不能改變他。特權變量也只能在構造函數中聲明。
好了,對象聲明介紹到這里,這些聲明模式都是由js的closure(閉包)特性所支持的,下面介紹閉包。
在一個閉包內,你可以暫且(?)理解成在構造函數內,內部函數總是可以訪問函數外部的變量和參數的。就算在內部函數return后,閉包內的所有變量都會被保存起來,就好像一個上下文一樣。下面我以一個例子說明這個問題,例子來源在群內,由YOK提供(例子已經被修改,只是用來簡單說明問題)。
說明:按test按鈕輸出相加的值,期望值為3。
<html>
<body>
<input type="button" id="test" value="test" />
<script>
function Test (x, y)
{
var x = x;
var y = y;
}
Test.prototype.add = function ()
{
alert(this.x + this.y);
}
var t = new Test(1, 2);
document.getElementById('test').onclick = t.add;
</script>
</body>
</html>
運行例子,但是輸出"NaN"。這是什么問題呢,我最初調試的時候,以為是this的問題,我原本理解成在add方法中this是指向test按鈕(其實this指向window對象),而他不包含x和y的兩個變量,所以輸出錯誤。首先,這個理解是正確的,但是你要如何修改才能獲取正確的結果呢。我們已經知道,在Test構造函數中,我們聲明的x,y是兩個私有變量,你不可能在外部訪問到,所以必須另覓他路。我們利用特權變量來解決。
<html>
<body>
<input type="button" id="test" value="test" NAME="test"/>
<script>
function Test (x, y)
{
var x = x;
var y = y;
this.add = function () // 特權變量,可以訪問私有變量,又對外公開
{
alert(x + y);
}
}
var t = new Test(1, 2);
document.getElementById('test').onclick = t.add;
</script>
</body>
</html>
上面呈現的是閉包的其中一個特性,下面用來說他的另外一個特性。
<html>
<body>
<input type="button" id="test" value="test" NAME="test"/>
<script>
function Test ()
{
var z = 1;
this.add = function ()
{
alert(z++);
}
}
var t = new Test();
document.getElementById('test').onclick = t.add;
</script>
</body>
</html>
每次輸出,值都會增加1,說明閉包內上下文就算add方法return后都會被保存。
最后說下怎么動態替換行為(這里是按鈕click的行為)。
<html>
<body>
<input type="button" id="test" value="test" NAME="test"/>
<script>
function Test ()
{
var z = 1;
var self = this;
var pBtn = null;
this.selfSubtract = function ()
{
z--;z--;
alert(z);
pBtn.onclick = self.selfPlus;
}
this.selfPlus = function ()
{
z++;
alert(z);
pBtn.onclick = self.selfSubtract;
}
this.getFunction = function (btn)
{
pBtn = btn;
return self.selfSubtract;
}
}
var t = new Test();
var btn = document.getElementById('test');
btn.onclick = t.getFunction(btn);
</script>
</body>
</html>
以上是我對他的一點見解,closure是js的一個特性而已,我們可以利用這個特性使設計更靈活,其他語言,我google到的好像叫Lua,不知道他是什么,他也支持。由于對js了解不深,請高手斧正確,enjoy it~~~ :)