標籤:
之前在看《Javascript 進階程式設計》一書中遇到過getter和setter,但因當時難於理解,且覺得用處較小,沒有細看,今日突然遇到了一種使用get&set讀寫對象屬性的方式。
//字面量建立對象var p={ //對象的成員:屬性&方法 name:"cj", work:function(){ console.log("working...."); }, _age:18, //一般常用底線開頭,表示該屬性只能有對象的方法進行訪問。 //get讀取p._age get age(){ return this._age; }, //set設定p._age set age(val){ if(val<0||val>150){ throw new Error("invalid value"); }else{ this._age=val; } }};console.log(p.age); //18console.log(p._age); //18p.age=30;console.log(p.age); //18console.log(p._age); //18
然後在網上搜到了一組類似的用法:
//建立一個類 var Person = function() { //屬性:姓名,注意要屬性名稱與get和set的名稱不能重複否則會報錯 this._username = ‘unknown‘; this._age = 0; } //在原型中給set和get方法 //在原型中get和set方法的名稱是一樣的,方便調用 Person.prototype = { set username(name) { // console.log(‘調用username的set方法‘); this._username = name; }, get username() { // console.log(‘調用了username的get方法‘); return this._username; } } var p = new Person(); console.log(p); console.log(p.username); //unknown p.username; p.username = ‘foo‘; console.log(p.username); //foo
但是沒能尋找到更多關於get和set的資訊,只能琢磨一下getter和setter:
ECMAScript中有兩種屬性:資料屬性和訪問器屬性。
資料屬性包含一個資料值的位置。在這個位置可以讀取和寫入值。
1、資料屬性:在使用字面量形式建立的對象中,直接定義在對象上的屬性,包含四個預設的屬性:
(1)[[configurable]]:表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問器屬性。該特性預設值為true。
(2)[[enumerable]]:表示能否通過for-in迴圈返回屬性。該特性預設值為true。
(3)[[writable]]:表示能否修改屬性的值。該特性預設值為true。
(4)[[value]]:包含這個屬性的資料值,讀取屬性值的時候,從這個位置讀;寫入屬性值的時候,把新值儲存在這個位置上,該特性預設值為undefined。
如果需要修改資料屬性,需要使用ECMAScript5中的object.defineProperty()方法。
var p={ name:"nicole"};Object.defineProperty(p,"name",{ value:"abc"})console.log(p.name); //abc
2、訪問器屬性:不包含資料值;他們包含一對兒getter&setter函數,有如下4個特性:
(1)configurable:表示能否通過delete刪除屬性從而定義新的屬性,能否修改屬性的特性,或者能否把屬性修改為資料屬性。該特性預設值為true。
(2)enumerable:表示能否通過for-in迴圈返回屬性。該特性預設值為true。
(3)get:在讀取屬性時調用的函數。該特性預設值為undefined;
(4)set:在寫入屬性時調用的函數。該特性預設值為undefined;
tip:_ 底線是一種常用的記號,用於表示只能通過對象方法訪問的屬性。
var book={ _year:2004, edition:1};Object.defineProperty(book,"year",{ //跟資料屬性不一樣,此處的year是訪問器屬性,_year是資料屬性。 get:function(){ return this._year; }, set:function(newValue){ if(newValue>2004){ this._year=newValue; this.edition+=newValue-2004; } }}) book.year=2005;alert(book.edition); //2
支援這種方法的瀏覽器有:IE9+(IE8隻是部分實現),Firefox4+,Safari5+,Opera12+,Chrome.舊版建立訪問器屬性,一般都是用兩個非標準的方法:_defineGetter_()和_defineSetter_()
3、定義多個屬性
var book={};Object.defineProperties(book,{ _year:{ writable:true, value:2004 }, edition:{ writable:true, value:1 }, year:{ get:function(){ return this._year; }, set:function(newValue){ if(newValue>2004){ this._year=newValue; this.edition+=newValue-2004; } } }})console.log(book._year); //2004console.log(book.edition); //1book.year=2005;console.log(book.edition); //2
使用ECMAScript5的Object.getOwnPropertyDescriptor(屬性所在的對象,屬性名稱),可以取得給定屬性的描述符,返回一個對象,對象包含相應的屬性。
如果是資料屬性,這個對象的屬性有:configurable,enumerable,writable,value;
如果是訪問器屬性,這個對象的屬性有:configurable,enumerable,get,set;
支援這個方法的瀏覽器有:IE9+,Firefox4+,Safari5+,Opera12+,Chrome。
++++var descriptor=Object.getOwnPropertyDescriptor(book,"_year");console.log(descriptor);var descriptor2=Object.getOwnPropertyDescriptor(book,"year");console.log(descriptor2);
第一個_year是資料屬性,第二個year是訪問器屬性。所以最終列印出的結果如下:
所以看完這裡,仍然不理解最初遇到的那種寫法是為何,姑且當做是在字面量對象中建立了訪問器屬性,來讀寫資料屬性吧。
JS中的get & set