對於面向對象編程語言(如java,.net,php,python等)來說,其最大的特點在於“面向對象”,而"面向對象"較為顯著的特征便是:封裝,繼承,多態。藉助”面向對象“的這些特征,通常地,一個類大致包括三大部分:屬性,方法和索引器,下麵定義的一個類就包括這三大部分(.Net 語言)。 我們知道, ...
對於面向對象編程語言(如java,.net,php,python等)來說,其最大的特點在於“面向對象”,而"面向對象"較為顯著的特征便是:封裝,繼承,多態。藉助”面向對象“的這些特征,通常地,一個類大致包括三大部分:屬性,方法和索引器,下麵定義的一個類就包括這三大部分(.Net 語言)。
public class OOClass { //定義屬性 private string _IDCard = ""; private string _UserName = ""; //定義方法 public string GetIDCard() { return _IDCard; } public string GetUserName() { return _UserName; } //定義索引器 private string Tel { get; set; } }
我們知道,JavaScript是一門”弱面向對象“編程語言,其沒有”對象“和”類“(註意:我們說JavaScript一切皆對象,這裡的對象與面向對象編程語言的對象含義是不同的),類是實現繼承的主要技術,對象是類的實例化,如果JavaScript要想實現繼承,則首先要具備類和對象的條件,只有具備了該條件,方可實現繼承(其實我們知道,JavaScript的原型和原型鏈實現繼承,我會在後面的文章中深入分析原型與原型鏈),那麼,在JavaScript中,是 什麼扮演類和對象角色呢?JavaScript對象及其屬性。如果要類比,那應該是這樣的關係:
一 兩種典型的對象定義方式
(一)函數表達式方式
1.定義一個Person對象
//定義Person對象 function Person() { }
2.為Person對象定義屬性
//為person對象定義屬性 Person._tel = "136xxx954xx"; Person.name = "Alan_beijing"; Person.sex = "Man"; Person.Address = "Shanghai";
3.為對象定義方法
//為person對象定義方法 Person.tel = function () { return this._tel; }
4.測試結果
//測試 alert(Person.name + "," + Person.sex + "," + Person.Address + "," + Person._tel);//Alan_beijing,Man,Shanghai,136xxx954xx alert(Person.SpeakLanguage());//Chinese And English
5.完整例子Code
//定義Person對象 function Person() { } //為person對象添加屬性 Person._tel = "136xxx954xx"; Person.name = "Alan_beijing"; Person.sex = "Man"; Person.Address = "Shanghai"; //為person對象添加方法 Person.tel = function () { return this._tel; } //測試 alert(Person.name + "," + Person.sex + "," + Person.Address);//Alan_beijing,Man,Shanghai alert(Person.tel());//136xxx954xxView Code
(二)對象字面量方式
1.定義對象同時為對象定義屬性和方法
var Person = { //為person對象定義屬性 _tel: "136xxx954xx", name: "Alan_beijing", sex: "Man", address: "Shanghai", //為person對象定義方法 tel: function () { return this._tel; } }
2.測試結果
//測試 alert(Person.name + "," + Person.sex + "," + Person.address);//Alan_beijing,Man,Shanghai alert(Person.tel());//136xxx954xx
3.完整例子Code
var Person = { //為person對象添加屬性 _tel: "136xxx954xx", name: "Alan_beijing", sex: "Man", address: "Shanghai", //為person對象添加方法 tel: function () { return this._tel; } } //測試 alert(Person.name + "," + Person.sex + "," + Person.address);//Alan_beijing,Man,Shanghai alert(Person.tel());//136xxx954xxView Code
(三)兩種方式比較
在兩種典型的對象定義方式中,對象字面量定義方式是比較常用的,其常用根本原因是其採用json的格式,簡潔而不繁瑣。
二 對象屬性種類
對象屬性,從屬性特性上來劃分,大致可分為兩大類,即數據屬性和訪問器屬性。
(一)數據屬性
數據屬性具有四個基本特性,即[[Configurable]],[[Enumerable]],[[Writable]]和[[value]]。
(1)[[Configurable]]:布爾類型(true或false,預設值為true),表示能否對對象屬性進行操作,大致包括如下操作:
- 刪除屬性
- 修改屬性特性
- 修改屬性類型,如將數據屬性修改為訪問器屬性
(2)[[Enumerable]]:能否通過for..in..迴圈遍歷
(3)[[Writable]]:能否修改屬性值
(4)[[value]]:屬性值
(二)訪問器屬性
訪問器屬性具有四個基本特性,即[[Configurable]],[[Enumerable]],[[Get]]和[[Set]]。
(1)[[Configurable]]:布爾類型(true或false),表示能否對對象屬性進行操作,大致包括如下操作:
- 刪除屬性
- 修改屬性特性
- 修改屬性類型,如將數據屬性修改為訪問器屬性
(2)[[Enumerable]]:能否通過for..in..迴圈遍歷
(3)[[Get]]:對象向外提供訪問對象屬性的函數
(4)[[Set]]:對象向外提供設置對象屬性的函數
(三)讀取數據的特性
ECMAScript 5提供了Object.getOwnPropertyDescriptor()方法,通過該方法,可以取得屬性特性值,該方法的原型如下:
其包含兩個參數(對象和對象屬性),其返回值是一個對象,如果是訪問器屬性,則這個對象的屬性有[[Configurable]],[[Enumerable]],[[Get]],[[Set]];若對象屬性為數據屬性,則返回[[Configurable]],
[[Enumerable]],[[writable]]和[[value]]。 下列代碼,先定義一個對象Person,然後通過ECMAScript 5提供的函數defineProperties()為該對象添加四個數據屬性(_tel,name,sex和address)和一個訪問器屬
性(telephone),其中telephone訪問器屬性具有兩個函數set()和get(),然後,我們通過getOwnPropertyDescriptor()函數訪問它們的四個特性值。
//定義對象 var Person = { } //為對象添加屬性 Object.defineProperties(Person, { //為person對象添加屬性 _tel: { value: "136xxx954xx" }, name: { value: "Alan_beijing" }, sex: { value: "Man" }, address: { value: "Shanghai" }, //訪問器 telephone: { get: function () { //var strName = "name:" + name; //return strName; return this._tel; }, set: function (tel) { _tel = tel; } } }) //數據屬性 var dataProp = Object.getOwnPropertyDescriptor(Person, "_tel"); alert(dataProp.value);//136xxx954xx alert(dataProp.configurable);//false alert(dataProp.writable);//false alert(dataProp.enumerable);//false //訪問器屬性 var visitProp = Object.getOwnPropertyDescriptor(Person, "telephone"); alert(visitProp.configurable);//false alert(visitProp.enumerable);//false alert(typeof visitProp.get);//function alert(typeof visitProp.set);//function
我們再來看看下麵例子:下麵例子與上面例子有幾點區別:
區別1:上面的屬性通過defineProperties()定義在對象Person外,而下麵Person對象屬性都是定義在對象Persin內部的
區別2:結果不同,對於數據屬性,除了[[value]]相同外,其他三個特性([[Configurable]],[[Writble]],[[Enumerable]])恰好是相反的的(上面均為false,下麵均為true);對於訪問器屬性,除[[Configurable]]和[[Enumerable]]
屬性值相反外,上面代碼[[Get]]和[[Set]]能成功訪問,但是下麵代碼顯示undefined,說明索引器屬性不能在對象內部定義。
//定義對象 var Person = { _tel: "136xxx954xx", name: "Alan_beijing", sex: "Man", telephone: { get: function () { //var strName = "name:" + name; //return strName; return this._tel; }, set: function (tel) { _tel = tel; } } } //數據屬性 var dataProp = Object.getOwnPropertyDescriptor(Person, "_tel"); alert(dataProp.value);//136xxx954xx alert(dataProp.configurable);//true alert(dataProp.writable);//true alert(dataProp.enumerable);//true //訪問器屬性 var visitProp = Object.getOwnPropertyDescriptor(Person, "telephone"); alert(visitProp.configurable);//true alert(visitProp.enumerable);//true alert(typeof visitProp.get);//undefined alert(typeof visitProp.set);//undefined
總結:
1.可以通過defineProperties()函數為對象定義多個屬性;
2.訪問器屬性不能在對象內部定義,只能在對象外部定義;
3.在對象內部定義屬性與通過defineProperties()函數在對象外部定義,屬性特性值是相反的;
4.通過getOwnPropertyDescriptor()函數可以訪問對象屬性;
5.需要註意的是,訪問器屬性的[[Get]]和[[Set]]不是必須的;
三 對象屬性基本操作
(一)添加定義屬性
ECMAScript提供了definePropertie()和defineProperties()函數來為對象定義屬性,這種方式是在對象外部為對象定義屬性,當然,也可以在對象內部為對象定義屬性(訪問器屬性不可在對象內部定義,只能在外部定義)
//定義對象 var Person = { } //為對象添加屬性 Object.defineProperties(Person, { //為person對象添加屬性 _tel: { value: "136xxx954xx" }, name: { value: "Alan_beijing" }, sex: { value: "Man" }, address: { value: "Shanghai" }, //訪問器 telephone: { get: function () { //var strName = "name:" + name; //return strName; return this._tel; }, set: function (tel) { _tel = tel; } } })View Code
(二)訪問對象屬性的四個特性
如下為在對象外部定義屬性的訪問結果,內部定義訪問結果是相反的
//數據屬性 var dataProp = Object.getOwnPropertyDescriptor(Person, "_tel"); alert(dataProp.value);//136xxx954xx alert(dataProp.configurable);//false alert(dataProp.writable);//false alert(dataProp.enumerable);//false //訪問器屬性 var visitProp = Object.getOwnPropertyDescriptor(Person, "telephone"); alert(visitProp.configurable);//false alert(visitProp.enumerable);//false alert(typeof visitProp.get);//function alert(typeof visitProp.set);//functionView Code
(三)刪除/修改對象屬性
如下代碼,我們設置數據屬性address可修改,修改成功
//定義對象 var Person = { } //為對象添加屬性 Object.defineProperties(Person, { //為person對象添加屬性 _tel: { value: "136xxx954xx" }, name: { value: "Alan_beijing" }, sex: { value: "Man" }, address: { writable: true, value: "Shanghai" }, //訪問器 telephone: { get: function () { //var strName = "name:" + name; //return strName; return this._tel; }, set: function (tel) { _tel = tel; } } }) alert(Person.address);//Shanghai Person.address = "Beijing"; alert(Person.address);//BeijingView Code
如下代碼,我們先設置[[Configurable]] 只可讀(false),然後嘗試刪除address屬性,刪除失敗
//定義對象 var Person = { } //為對象添加屬性 Object.defineProperties(Person, { //為person對象添加屬性 _tel: { value: "136xxx954xx" }, name: { value: "Alan_beijing" }, sex: { value: "Man" }, address: { configurable: false, writable: true, value: "Shanghai" }, //訪問器 telephone: { get: function () { //var strName = "name:" + name; //return strName; return this._tel; }, set: function (tel) { _tel = tel; } } }) alert(Person.address);//Shanghai delete Person.address; alert(Person.address);//ShanghaiView Code
如下代碼,我們先設置[[Configurable]] 可操作(true),然後再刪除address屬性,刪除成功
//定義對象 var Person = { } //為對象添加屬性 Object.defineProperties(Person, { //為person對象添加屬性 _tel: { value: "136xxx954xx" }, name: { value: "Alan_beijing" }, sex: { value: "Man" }, address: { configurable: true, writable: true, value: "Shanghai" }, //訪問器 telephone: { get: function () { //var strName = "name:" + name; //return strName; return this._tel; }, set: function (tel) { _tel = tel; } } }) alert(Person.address);//Shanghai delete Person.address; alert(Person.address);//UndefinedView Code
註意:當一旦定義[[Configurable]]為false時,再也變不回去了
//定義對象 var Person = { } //為對象添加屬性 Object.defineProperties(Person, { //為person對象添加屬性 _tel: { value: "136xxx954xx" }, name: { value: "Alan_beijing" }, sex: { value: "Man" }, address: { configurable: false, writable: true, value: "Shanghai" }, //訪問器 telephone: { get: function () { //var strName = "name:" + name; //return strName; return this._tel; }, set: function (tel) { _tel = tel; } } }) Object.defineProperty(Person, "address", { configurable:true })
上述代碼先將addess屬性的特性[[configurable]]設置false,然後又將其修改為true,修改失敗,因為[[configurable]]特性一旦設置為false,就再也不可改變。
[[configurable]]和[[writable]]區別?
前者操作屬性特性,如刪除屬性,修改屬性,更改屬性類型;後者操作屬性值,如更改屬性值。兩者沒有直接關係,即不管[[configurable]]的值是怎樣,一個屬性的值能否可修改,是由[[writable]]決定的,而不受[[configurable]]影響。
四 參考文獻
【01】JavaScript 高級程式設計(第三版) (美)Nicholas C.Zakas 著 李松峰 曹力 譯
【02】JavaScript 權威指南 (第6版) David Flanagan 著
五 已發佈文章
六 版權區
- 感謝您的閱讀,若有不足之處,歡迎指教,共同學習、共同進步。
- 博主網址:http://www.cnblogs.com/wangjiming/。
- 極少部分文章利用讀書、參考、引用、抄襲、複製和粘貼等多種方式整合而成的,大部分為原創。
- 如您喜歡,麻煩推薦一下;如您有新想法,歡迎提出,郵箱:[email protected]。
- 可以轉載該博客,但必須著名博客來源。