JavaScript中的私人/靜態屬性介紹

來源:互聯網
上載者:User

•類比塊級範圍
大家都知道在JavaScript中沒有塊級範圍的概念,我們可以通過使用閉包來類比實現塊級範圍,看下面的樣本: 複製代碼 代碼如下:(function () {
for (var i = 0; i < 10; i++) {
//Do Nothing
}
alert(i); //輸出10
})();

第6行可以訪問到for迴圈塊中的變數i,如果我們稍微修改以上代碼,把for迴圈塊放置在閉包中,情況就不一樣了: 複製代碼 代碼如下:(function () {
(function () {
for (var i = 0; i < 10; i++) {
//Do Nothing
}
})();
alert(i); //Error: 'i' is undefined
})();

在第8行訪問變了i時,出現錯誤,實現了我們想要的塊級範圍。
•私人屬性
在JavaScript中沒有塊級範圍的概念,同樣也沒有私人屬性的概念,但是存在私人變數。如果我們想把一些資料封裝隱藏起來要怎麼做呢?想必大家可能已經想到了,可以通過使用閉包+私人變數的方式來實現對象的私人屬性。
<1>.執行個體私人屬性
執行個體私人屬性的特點就是每個對象都會包含獨立的屬性,對象和對象之間沒有共用。為了實現這個目標,可以在建構函式中增加一個私人變數,然後定義公用方法來訪問這個私人變數,就如同其他OO語言的setter和getter一樣,下列樣本就實現了執行個體的私人屬性: 複製代碼 代碼如下://執行個體私人變數
function MyObject(name) {
//定義私人變數
//注意:此處沒有用this.name,如果使用this.name變成公用屬性了
var privateName = name;
//定義私人熟悉
var privateFunction = function () {
return "Private Function";
}
//公用方法訪問私人熟悉
MyObject.prototype.getName = function () {
return privateName;
}
MyObject.prototype.getFunction = function () {
return privateFunction();
}
}
var moGyy = new MyObject("gyy");
alert(moGyy.getName()); //輸出gyy
alert(moGyy.getFunction()); //輸出Private Function
var moCyy = new MyObject("cyy");
alert(moCyy.getName()); //輸出cyy
alert(moCyy.getFunction()); //輸出Private Function

在上面的樣本中建立的兩個對象moGyy和moCyy的getName返回不同的值,同時如果想調用私人方法同樣也需要公用介面。上面的樣本中兩個公用函數之所以能訪問私人變數,是因為兩個公用函數都是閉包,而閉包的範圍鏈中包含了包含函數的變數對象,因此在進行變數尋找時,順著範圍鏈可以訪問包含函數中的私人變數。在上面的樣本中把公用方法添加到MyObject的原型中,目的是防止每次建立對象都建立功能一樣的兩個函數執行個體。
<2>.靜態私人屬性
在有些情況下我們可能希望資料全域共用,那麼可能就會用到靜態屬性,我們還是希望這個屬性為私人的,那麼怎樣實現靜態私人屬性呢?首先這個私人應該在建構函式的外部,為了把建構函式外部的變數和建構函式結合為一體,可以使用閉包把私人變數和建構函式都包含在其範圍中,為了在閉包外面訪問內部的建構函式,可以使用一個全域的變數來引用建構函式,如下程式碼範例: 複製代碼 代碼如下://靜態私人變數和執行個體私人變數
(function () {
//定義私人變數
var staticPrivateValue = "";
//建構函式,把構織函數賦值給一個全域的變數
MyObject = function (name) {
//定義執行個體變數
this.name = name;
};
//定義兩個公用方法用於訪問私人變數,再一次把公用方法添加到原型中
MyObject.prototype.getPrivateValue = function () {
return staticPrivateValue;
}
MyObject.prototype.setPrivateValue = function (value) {
staticPrivateValue = value;
}
})();
var mo = new MyObject("jeff-gyy");
mo.setPrivateValue("gyycyy"); //設定私人屬性的值
alert(mo.getPrivateValue()); //輸出gyycyy
alert(mo.name); //輸出jeff-gyy
var mo1 = new MyObject("jeff-cyy");
alert(mo1.getPrivateValue()); //輸出gyycyy
alert(mo1.name); //輸出jeff-cyy

從上面的代碼來看mo1調用getPrivateValue函數返回的值就是mo設定的值"gyycyy",為什麼會這樣呢?首先我們定義了一個匿名函數並立即調用函數,函數包含了私人變數staticPrivateValue,那麼為MyObject定義的兩個原型方法其實通過閉包的範圍鏈可以訪問在包含函數的私人變數,也就是getPrivateValue和setPrivateValue兩個函數的範圍鏈中都包含了匿名函數的變數對象,我們知道範圍鏈中包含的變數對象其實就是一個指標,所以建立的兩個對象通過公用方法房屋私人變數時,其實訪問的都是匿名函數的變數對象中的staticPrivateValue,因此實現變數執行個體間共用的目的。從傳統OO語言的角度來看我們實現的靜態屬性其實並不是真正意義上的靜態,只是實現了靜態屬性執行個體共用的特點。
<3>.模組模式和增強模組模式
還有一種全域共用資料的方式就是singleton, 可以使用模組模式來實現Object類型的單例模式,也可以使用增強模組模式實現自訂類型的單例模式,如下樣本: 複製代碼 代碼如下://自訂建構函式
var mo = new function () {
//私人變數
var privateValue = "";
//普通模組模式
return {
publicValue: "public",
//訪問私人變數
getPrivateValue: function () {
return privateValue;
},
setPrivateValue: function (value) {
privateValue = value;
}
}
}();
mo.setPrivateValue("private value");
alert(mo.getPrivateValue());
alert(mo.publicFunction());

模組模式使用匿名函數來封裝內部實現,就上面的樣本匿名函數中包含了私人變數privateValue,返回的對象中的公用函數通過閉包的範圍鏈訪問包含函數中的私人變數,由於定義的匿名函數被立即調用,因此變數mo引用的是返回的對象。上面的單例模式返回的是一個Object對象,可以使用增強模組模式實現自訂類型的單例模式: 複製代碼 代碼如下://增強模組模式
//自訂建構函式
function MyObject(name) {
this.name = name;
};
//自訂建構函式
var mo = new function () {
//私人變數
var privateValue = "";
//增強模組模式
var o = new MyObject("gyycyy");
o.publicValue = "public";
//訪問私人變數
o.getPrivateValue = function () {
return privateValue;
}
o.setPrivateValue = function (value) {
privateValue = value;
}
return o;
}();
mo.setPrivateValue("private value");
alert(mo.getPrivateValue());
alert(mo.publicFunction());

以上程式碼範例實現了MyObject的單例模式。
最後需要提一點的是使用閉包有利也有弊,由於閉包範圍鏈引用包含函數的變數對象,因此會佔用額外的記憶體,而且進行變數尋找是也需要通過範圍鏈,因此會消耗尋找時間,閉包越深情況更嚴重。另外在IE(早些版本)中由於記憶體回收機制使用引用計數,因此可能會出現循環參考的情況,導致記憶體泄露,如下樣本: 複製代碼 代碼如下:function assignHandler(){
var element = document.getElementById("someElement");
element.onclick = function(){
alert(element.id);
};
}

在上面的代碼中建立了一個閉包作為element的事件,該閉包引用了包含函數assingHandler的變數對象,而恰恰是對變數對象的引用使得element引用計數至少為1,因此element不會被回收,導致記憶體泄露。修改的方法大家可以想想。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.