JavaScript物件導向之屬性實現

來源:互聯網
上載者:User
作者:Truly
日期:2007.8.3

在我前面一篇文章《在JavaScript中使用物件導向》中我們介紹了MSDN的一篇文章《使用物件導向的技術建立進階 Web 應用程式》,作者簡單介紹了JavaScript物件導向的一些關鍵技術,但是作者在講到閉包概念的時候犯了一個明顯的錯誤:“正常情況下,無法從函數以外訪問函數內的本地變數。函數退出之後,由於各種實際原因,該本地變數將永遠消失”詳見原文。事實上這段描述是錯誤的。

請先看如下代碼:

<script>
function Test(abc)
{
this.g = function(){debugger;};
}

var p = new Test(2);
p.g();
</script>

如果你啟用了IE的調試功能,並安裝了指令碼調試器,例如VS,那麼你在程式提示調試的時候進入調試,此時你可以醒目的發現abc依然存在,並且完好的儲存了正確的值,而並非永遠消失。但是這也不是我本文要討論的重點,只是希望大家以後能夠多動手,多實踐,像MS ASP.NET AJAX 團隊的軟體設計工程師都會犯這種錯誤,更何況諸位呢?

本文要討論的是物件導向編程中常用的屬性,但是在JavaScript中屬性則無法像進階程式設計語言那樣可以直接使用,看起來更像方法,這種實現方式也有人稱之為閉包,但本文以屬性相稱。

屬性是對私人變數的一種保護手段,同時提供了像public變數一樣的使用效果,近代的進階程式設計語言例如C#和Java都支援了屬性這一特點。

我們知道,函數的入口參數被聲明為該函數的本地變數,而對於本地變數,像我前面《在JavaScript中使用物件導向》關於全域變數和局部變數中描述的那樣,由於其範圍僅限於函數內部,所有無法在外部對其進行訪問,例如p.abc不會返回p內部的abc變數。這一點跟進階程式設計語言完全一致,你無法在類外部存取其private變數,但是我們可以藉助public方法來返回私人變數。所以進階程式設計語言如Java,C#等中屬性的作用,就是保護私人變數。像C#這門語言,屬性最終會由編譯器編譯為get_屬性名稱()這樣的方法,當我們使用某個屬性時,實質上是調用一個方法。

使用物件導向的技術建立進階 Web 應用程式》的作者認為是由於方法的定義才使局部變數存活下來,這一點是不正確的,具體我們前面已經分析過了,如果你仍有疑問,那麼再仔細研究下面的代碼:

function Person(name, age) {
    this.getName = function() {debugger; return 1; };
}
var o = new Person(1,2);
o.getName();    // 進入調試後發現name=1
var t = new Person(2,4);
t.getName();    // 進入調試後發現name=2
o.getName();    // 進入調試後發現name=1,並未受到其它執行個體的影響

對於這個問題,我起初也認為是因為變數有引用才沒被銷毀,最後證明局部變數在對象銷毀前其內部的變數不會銷毀。

同時那篇文章中另外一段也是不準確的:
注意,這些私人成員與我們期望從 C# 中產生的私人成員略有不同。在 C# 中,類的公用方法可以訪問它的私人成員。但在 JavaScript 中,只能通過在其閉包內擁有這些私人成員的方法來訪問私人成員(由於這些方法不同於普通的公用方法,它們通常被稱為特權方法)。因此,在 Person 的公用方法中,仍然必須通過私人成員的特權訪問器方法才能訪問私人成員

關於這一點,他的表述相當模糊,事實上我們可以這樣理解:

在C#中我們可以在類的任何方法中訪問類的私人成員變數,
而在JavaScript中,只能使用在function方式中定義的方法對私人成員訪問,而無法在prototype方式定義的方法中訪問。

如果這樣講你還不能理解的話,那麼還可以這樣理解,在JavaScript中的私人變數無法在其聲明函數外訪問,例如:

function Person()
{
    var ttt;
}

永遠不能在{}外部試圖訪問ttt

現在我們更加深入的理解了變數範圍在JavaScript中的特點。

前面講了進階程式設計語言中屬性的種種好處,又研究了JavaScript對私人變數的保護,那麼您對JavaScript中屬性的實現應該非常清楚了,這裡引用《使用物件導向的技術建立進階 Web 應用程式》文中的一段範例程式碼:

function Person(name, age) {
    this.getName = function() { return name; };
    this.setName = function(newName) { name = newName; };
    this.getAge = function() { return age; };
    this.setAge = function(newAge) { age = newAge; };
}

關於屬性在實際中的應用及其優點,將在我下一篇文章介紹自訂事件中講解。

後記:本來打算在這裡講述如何在JavaScript中實現物件導向中的一些特性,比如用“屬性”這一現代編程概念體現的對象的封裝性:不直接操作類的資料內容,而是通過訪問器進行訪問,即藉助於get和set對私人成員的值進行讀寫。最後卻演變成為一個白馬是不是馬的哲學討論,真是汗顏。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.