物件導向Javascript - 封裝

 Sat, 22 Mar 2008 14:46:44 +0800

不久前在論壇發表的文章。在國外blog有看過不少這方面的好文章,不過在國內論壇上比較少看到人討論,所以在幫人解決問題後,順手寫了這一篇。


好像比較少人在這裡分享這一方面的知識,很可惜。之前在國外網站上看了一些不錯的東西,在這裡分享一下:)

個人在學習Javascript的過程中,最常被困擾的問題來源,其實背後都是變數範圍解析的問題。而應用變數範圍解析,就可以達到資料封裝的效果。所以先來講一下變數範圍解析。(這些東西都定義在ECMA-262第三版,但是說實在的,這個標準寫得像是天書...)

可以把Javascript看成用 execution context 為單位組成的結構,javascript在執行的時候,會在不同的 execution context 間切換。 execution context 有三種: Global , Function 以及 Eval 。Javascript變數解析的規則叫做 scope chain ,每次進入不同的 execution context ,執行環境就會為它建立一個 scope chain ,結構類似一個堆疊,目前正在執行的 execution context 放在堆疊的最上面,然後依次是其他的 execution context 。舉例來說,當函數a裡面定義了另一個函數b,那在執行函數b裡面的程式時, scope chain 會像是:b->a->Global,Javascript會依照這個順序尋找變數、函數等的定義。(還是有點像天書)

接下來用一個例子來看:

function test() {
global1 = 1;
var private1 = 2;
}
function check() {
alert(global1);
}
test();
check();

猜猜會發生甚麼事?會跳出一個內容為1的對話框。用 scope chain 規則來解釋:當執行test()時,碰到了global1這個東西,在test函數裡面並沒有定義,所以執行環境到 Global 找,也沒找到,然後執行環境就在 Global 定義了一個變數,名稱叫做global1,然後把1這個值assign給他。之後執行check(),碰到 global1這個東西,在check函數裡面也沒定義,所以執行環境跑到 scope chain 中的下一個 execution context ,也就是 Global 中找,然後找到了。所以alert()就會秀出1。

如果在上面的例子後面加入一個函數:

function check1() {
alert(private1);
}

然後執行check1(),就會出現 "private1 undefinded" 的錯誤訊息。

如果我想讓不在 scope chain 中的其它函數也能使用到某個變數或方法,那要用到 this

function test() {
this.public1 = "test.public1!!!";
}
function check() {
var a = new test();
alert(a.public1);
}
check();

透過 new 以及 this ,就可以在check()函數中取得定義在test()中的東西了。


有了以上,就可以寫出既有封裝又有公開資料的物件了:

function test() {
var private1 = "I'm private variable 'private1'!";//私有成員變數
this.public1 = "I'm public valiable 'public1'!";//公開成員變數
function getPrivateFriend() {//私有成員函數
alert(private1);
}
this.getPrivatePublic = function() {//公開成員函數
getPrivateFriend();
}
}
try {//為了讓a.getPrivateFriend()執行結果看得到,所以用try捕捉錯誤訊息
var a = new test();
a.getPrivatePublic();
alert(a.public1);
alert(a.private1);
a.getPrivateFriend();
} catch(E) {alert(E);}

簡單的總結:

  1. 在函數中用 var 定義變數,則可以將此變數視為此函數物件的私有變數
  2. 在函數中用 this.名稱 來定義變數或方法,則可將此變數或方法視為此函數物件定義的公有變數或公有方法。
  3. 在函數中直接用 function 定義函數,則此函數可視為函數物件的私有方法