萬盛學電腦網

 萬盛學電腦網 >> 腳本專題 >> javascript >> JavaScript--數據屬性和訪問器屬性

JavaScript--數據屬性和訪問器屬性

   在JavaScript中最基本的創建一個對象的方法是new一個Object()的實例,然後再為其添加屬性與方法,下例創建一個包含屬性name的person對象,name屬性的特征值為”xiaochang”:

  var person = new Object();person.name = "xiaochang";person.say = function(){ console.log("Hi, my name is " + this.name);};person.say(); //Hi, my name is xiaochang

  EAMAScript. 5 定義了描述這些屬性特征的各類特性,包括數據屬性和訪問器屬性。

  數據屬性:該屬性包含了一個數據值的位置,它包含了4個描述行為的特性:

  1. [[Configurable]]:表示是否能通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,能否把屬性修改為訪問器屬性。

  2. [[Enumerable]]:表示能否用for-in循環返回。

  3. [[writable]]:表示能否修改屬性的值。

  4. [[Value]]:包含這個屬性的數據值。讀取屬性值的時候從這個位置讀,寫入屬性值的時候更新到這個位置,默認值為undefined。

  直接在對象上定義的屬性的數據特性默認如下:

  1. [[Configurable]]:true

  2. [[Enumerable]]:true

  3. [[writable]]:true

  4. [[Value]]:”xiaochang” (初始時的賦值)

  這些特性不能直接被訪問,要修改屬性的特性只能通過Object.defineProperty( )方法,該方法包含三個參數:屬性所在的對象,屬性的名字,描述符對象[configurable|enumerable|writable|value]。例如:

  var person = { age:100 };Object.defineProperty(person,"name",{ configurable:false, writable:false, value:"xiaochang"});Object.defineProperty(person,"tall",{ value:160});for(attr in person){ console.log(attr); //name,age}console.log(person.name); //xiaochangperson.name="CC"; //為name屬性指定新值console.log(person.name); //xiaochangdelete person.name; //刪除name屬性console.log(person.name); //xiaochangconsole.log(person.age); //100person.age=200; //為age屬性指定新值console.log(person.age); //200delete person.age; //刪除age屬性console.log(person.age); //undefinedconsole.log(person.tall); //160person.tall = 160; //修改tall屬性的值console.log(person.tall); //160delete person.tall; //刪除name屬性console.log(person.tall); //160

  分析例子可知直接在對象上定義的屬性,如age,[[Configurable]],[[Enumerable]],[[writable]]都被設置為true。

  屬性name的[[Configurable]],[[writable]]被設置為false,所以無法修改和刪除。

  調用Object.defineProperty( )方法時,如果不顯示指定configurable,enumerable,writable的值,就默認為false,如屬性tall。

  另外需要注意的是當configurable設置為false後無法再將其改為true,且除了writable之外,無法修改其它特性。在configurable為true的情況下可多次調用Object.defineProperty( )修改同一屬性。

  在非嚴格情況下修改無法配置的屬性操作會被忽略,在嚴格模式下會拋出錯誤。

  訪問器屬性:包含getter和setter函數。讀取訪問器屬性時,調用getter函數,返回有效的值;在寫入訪問器屬性時,調用setter函數傳入新值。它包含了4個特性:

  1. [[Configurable]]:表示是否能通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,能否把屬性修改為訪問器屬性。

  2. [[Enumerable]]:表示能否用for-in循環返回。

  3. [[Get]]:讀取屬性時調用的函數,默認undefined。

  4. [[Set]]:寫入屬性時調用的函數,默認undefined。

  getter和setter不一定要成對出現,只有getter函數證明該屬性只讀不可寫,嘗試寫入在非嚴格模式下會被忽略,嚴格模式會拋出錯誤。相同,只有setter函數證明只寫不能讀,嘗試讀在非嚴格模式下返回undefined,嚴格模式則拋出錯誤。

  訪問器屬性無法直接定義,必須使用Object.defineProperty( )來定義,如下:

  var person = { _name:"xiaochang", //name屬性只讀不可寫 _age:100, //age屬性只寫不可讀 _tel:123456 //tel屬性可讀可寫};Object.defineProperty(person,"name",{ get:function(){ return this._name; }});Object.defineProperty(person,"age",{ set:function(newage){ this._age = newage; }});Object.defineProperty(person,"tel",{ get:function(){ return this._tel; }, set:function(newtel){ this._tel= newtel; }});console.log(person.name); //"xiaochang"person.name = "CC"; //嘗試修改name屬性console.log(person.name); //"xiaochang"console.log(person.age); //不可讀屬性,undefinedperson.age = 200; //修改ageconsole.log(person._age); //直接讀取對象方法才能訪問的屬性,可以看到值已更新200console.log(person.tel); //123456person.age = 654321; //更新telconsole.log(person.tel); //654321

  屬性前面的下劃線表示只能通過對象方法訪問的屬性,當我們調用person.name時實際調用了name屬性的getter函數(直接調用person._name可得到相同的結果,這樣做訪問器就沒什麼意義了)。通過上面例子中可以很清晰的看出屬性與訪問器之間的關系。

  支持Object.defineProperty( )方法的浏覽器有IE9+(IE8是第一實現Object.defineProperty( )方法的浏覽器,但僅限於DOM對象,且只能創建訪問器屬性)、Firefox4+、Safari5+,Opera12+、Chrome。在不支持Object.defineProperty( )方法的浏覽器中不能修改[[Configurable]],[[Enumerable]]。

  在Object.defineProperty( )方法之前,要創建訪問器屬性,一般使用非標准的方法:__defineGetter__()和__defineSetter__(),這兩個方法最初在Firefox引入,後來chrome1和Opera9.5也支持。改寫上面的tel屬性訪問器如下:

  person.__defineGetter__("tel",function(){ return this._tel;});person.__defineSetter__("tel",function(newtel){ this._tel = newtel;});

  ECMAScript. 5還定義Object.defineProperties( )方法,該方法包含兩個參數:屬性所在的對象,多個屬性的名字和其描述符對象組成的對象。其作用於Object.defineProperty( )相同,區別是可一次性定於多個屬性。支持該方法的浏覽器有IE9+、Firefox4+、Safari5+,Opera12+、Chrome。上面的例子可以改寫如下:

  var person = { _name:"xiaochang", //name屬性只讀不可寫 _age:100, //age屬性只寫不可讀 _tel:123456 //tel屬性可讀可寫};Object.defineProperties(person,{ name:{ get:function(){ return this._name; } }, age:{ set:function(newage){ this._age = newage; } }, tel:{ get:function(){ return this._tel; }, set:function(newtel){ this._tel= newtel; } }});

  對於上述講到的屬性特性,ECMAScript. 5 給出了可以取得給定屬性的描述符的方法Object.getOwnPropertyDescriptor(),該方法包含兩個參數:屬性所在的對象,要讀取其描述符的屬性名稱。方法返回一個對象。如針對上面的例子可得:

  var descriptor = Object.getOwnPropertyDescriptor(person,"tel");for(attr in descriptor ){ console.log(attr+":"+descriptor[attr]);}運行結果如下:get:function (){return this._tel;}set:function (newtel){this._tel= newtel;}enumerable:falseconfigurable:false

copyright © 萬盛學電腦網 all rights reserved