JavaScript對象(二)

屬性的getter和setter

JavaScript的屬性值可以用getter和setter方法代替,由getter和setter定義的屬性稱為存取器屬性。存取器屬性是可以繼承的。
用例子說明:

var  p = {
     //x和y是普通的可讀寫的數據屬性
     x: 1.0,
     y: 1.0,
     // r是可讀寫的存取器屬性,它有getter和setter
     // 函數體結束后不要忘記帶上逗號
     get r(){   return Math.sqrt(this.x*this.x + this.y*this.y)  },
     set r(newValue){
          var oldValue = Math.sqrt(this.x*this.x + this.y*this.y);
          var ratio = newValue/oldValue;
          this.x *= ratio;
          this.y *= ratio;
     },
     // theta是只讀存取器屬性,它只有getter方法
     get theta(){return Math.atan2(this.y,this.x)},  
};
console.log(p);  // ==> (1,1)  r = 1.41421356  theta = 0.785398
p.r = 2;
console.log(p);  // ==> (1.41421356,1.41421356)  r = 2  theta = 0.785398

屬性特性

數據屬性特性分為:值(value),可寫性(writable),可枚舉性,可配置性。
存取器屬性特性分為:讀取(get),寫入(set),可枚舉性,可配置性。
我們創建的屬性默認都是可寫、可枚舉、可配置的。
我們通過例子來介紹一個方法(Object.definePeoperty()):

// 我們可以調用Object.definePeoperty()來設置對象屬性的特性
// 我們可以調用Object.definePeoperty()來設置對象屬性的特性
/*
 *參數1:傳入的對象   (Object)
 *參數2:要創建或者修改的屬性的名稱 (String)
 *參數3:屬性的特性(對于新創建的自有屬性四個屬性默認都為false或者undefined,對于已有屬性來說,默認的特性值是沒有做任何修改的)
 *(注意:此方法 只能修改自有屬性或者是創建自有屬性,但是不能修改繼承屬性)。
 */
//----看點1
// 簡單介紹一下 方法的使用
var obj = {};
Object.defineProperty(obj,"x",{value:2017,
                               writable:true,
                               enumerable:true,
                               configurable:true});
document.write(obj.x+"<br/>");  // ==> 2017
// 這個方法同樣是有返回值的,是將修改的對象返回
var obj1 = Object.defineProperty({},"x",{value:2017,
                                         writable:true,
                                         enumerable:true,
                                         configurable:true});
document.write(obj1.x+"<br/>");  // ==> 2017
//-----------------------------------------------------------
//----看點2
// 對于新創建的自有屬性,四個屬性的默認值都為false或者undefined
var obj2 = Object.defineProperty({},"x",{});
document.write(obj2.x+"<br/>");  // ==> undefined
obj2.x = 2017;
document.write(obj2.x+"<br/>");  // ==> undefined
//-----------------------------------------------------------
//----看點3
// 對于已有屬性來說,默認的特性值是沒有做任何修改的
var obj3 = {x:2017}; // x 屬性是可寫、可枚舉、可配置的
Object.defineProperty(obj3,"x",{});  // 屬性描述中沒有做任何修改
obj3.x = 2000;
document.write(obj3.x+"<br/>");  // ==> 2000 說明x屬性依然是可寫的
//-----------------------------------------------------------
//----看點4
// 此方法 只能修改自有屬性或者是創建自有屬性,但是不能修改繼承屬性
var obj4 = Object.create(obj3);
var obj4_x = obj4.x;   // 用一個對象來引用obj4.x屬性
document.write(obj4.hasOwnProperty("x")+ "<br/>"); //==> false x不是自有屬性
Object.defineProperty(obj4,"x",{}); // 創建x屬性并且覆蓋繼承的屬性
document.write(obj4.hasOwnProperty("x")+ "<br/>"); //==> ture 
// 從上面可以看出,通過此方法,obj4 創建了x屬性,并且覆蓋了繼承的x屬性
document.write(obj4.x+"---"+obj4_x+ "<br/>");//undefined---2000
obj4.x = 123123; // 嘗試修改x自有屬性,發現無效,原因是writable 為false
document.write(obj4.x+"---"+obj4_x+ "<br/>");//undefined---2000
// 從上面可以看出,新創建的自有屬性x,屬性描述都是默認值,所以value為undefined
//-----------------------------------------------------------
//----看點5
// 看看 數據類型屬性,是可以修改成存取器屬性的
var obj5 = {x:888};
Object.defineProperty(obj5,"x",{get:function(){return 2017}});
document.write(obj5.x + "<br/>"); // ==> 2017
obj5.x = 123;  // 由于存儲器屬性沒有set方法,所以是只讀屬性,不能進行修改
document.write(obj5.x + "<br/>"); // ==> 2017
//-----------------------------------------------------------
//----看點6
/*
 *Object.defineProperties() 可以修改一個對象的多個屬性描述
 *參數1:對象
 *參數2:一個映射列表(也成對象,字典),包括屬性名,屬性描述
 */
var obj6 = Object.defineProperties({},{x:{value:100,writable:true,enumerable:true,configurable:true},
"y":{value:200}});
document.write(obj6.x +"---"+ obj6.y + "<br/>"); // ==> 2017

我們來看看如果給Object復制屬性,而且這些屬性的特性也一并復制。

// 復制屬性的特性
/*
 *給Object.prototype(原型)添加一個不可枚舉的extend()方法。
 *這個方法繼承自調用它的對象,將作為參數傳入的對象的屬性一一復制,
 *除了值之外,也要復制屬性的所有特性,除非在目標對象中存在同名的屬性,
 *參數對象的所有自有對象(包括不可枚舉的屬性)也要意義復制。
 */
Object.defineProperty(Object.prototype,
       "extend",
       {
        writable:true,
        enumerable:false, // 不可枚舉
        configurable:true,
        value:function(obj){ // 值為一個函數
            //獲取所有的自有屬性,包括不可枚舉的
            var names = Object.getOwnPropertyNames(obj);
            // 遍歷
            for(var i = 0; i < names.length; i++){
                // 如果屬性中已經存在,則跳過
                if(names[i] in this) continue;
                // 獲取obj中的屬性的描述符
                var desc = Object.getOwnPropertyDescriptor(obj,names[i]);
                // 用它給this創建一個屬性
                Object.defineProperty(this,names[i],desc);
            }
        }
});

對象的三個屬性

對象的三個屬性是原型(prototype)、類(class)和可擴展性(extensible)。

  • 原型屬性
    原型屬性是在實例對象創建之初就設置好的,之前我們提到的,通過對象直接量創建的對象,原型是Object.prototype。通過new創建的對象,原型是構造函數的prototype。通過Object.create()創建的對象,原型是第一個參數。可以通過Object.getPrototypeOf()來查詢它的原型。也可以通過isPrototypeOf()方法來檢測一個對象是否是另一個對象的原型(或處于原型鏈中),例如p.isPrototypeOf(o)來檢測p是否是o的原型。
  • 類屬性
    對象的類屬性(class)是一個字符串,用來表示對象的類型信息。
    因為JS沒有提供設置這個屬性的方法,我們只能通過間接的方法來查詢它,默認的toString()方法(繼承自Object.prototype)返回[object class]這種格式的字符串,所以我們需要提取返回來的字符串的第8個位置到倒數第二個位置之間的字符串。(有個棘手的問題是,很多對象重寫了toString()方法,為了能夠調用正確toString()版本,必須簡介地調用Function.call()方法)。看例子:
//這個函數用來獲取對象的class屬性
function classof(obj){
    if(obj === null) return "Null";
    if(obj ===undefined) return "Undefined";
    return Object.prototype.toString.call(obj).slice(8,-1);
}
// 簡單的輸出函數
function printClassName(obj){
    document.write(classof(obj)+"<br/>");
}
printClassName(null);    //==>Null
printClassName(1);       //==>Number
printClassName("");      //==>String
printClassName(false);   //==>Boolean
printClassName({});      //==>Object
printClassName([]);      //==>Array
printClassName(/./);     //==>RegExp
printClassName(new Date());//==>Date
printClassName(window);  //==>Window
function f(){}   // 定義一個自定義構造函數
printClassName(new f());  //==>Object
  • 可擴展性
    對象的可擴展性用以表示是否可以給對象添加新屬性。所有的內置對象和自定義對象都是現實可擴展的。我們可以通過(Object.esExtensible())來判斷該對象是否是可擴展的。如果我們想將一個對象轉為不可擴展的,需要調用Object.preventExtensions()。需要注意的是,一旦對象轉成不可擴展的,就無法再將其轉化回可擴展的了,而且這個方法只影響對象本身的可擴展性。
    Object.seal()方法是將對象設置成不可擴展的,同時還將對象的所有自有屬性設置成不可配置的,但是不更改對象屬性的可寫屬性,也就是將對象封閉。
    Object.isSeal()方法是來檢測對象是否封閉。Object.freeze()`是嚴格鎖定對象,不僅將對象設置為不可擴展的和將其屬性設置成不可配置的之外,還可以將它自有的所有數據屬性設置成只讀的(讀取器屬性的不受影響)。

序列化對象

對象序列化是指將對象的狀態轉換為字符串,也可以將字符串還原為對象。
Json.stringify()用來序列化JS對象的。
Json.parse()用來還原JS對象。
注意:JSON的語法是JavaScript語法的子集,它并不能代表JavaScript里的所有值。支持對象、數組、字符串、無窮大數字、true、false、null,并且它們可以序列化和還原。NaN、Infinity和- Infinity序列化的結果是null。而函數、RegExp、Error對象和undefined值不能序列化和還原。序列化只能序列化對象可枚舉的自有屬性,對于不能序列化的屬性會將屬性省略。這兩個方法接受第二個參數和第三個參數,大家可以看看文檔。

var mObj = {
            x:1,
            y:{z:[false,null,"string"]},
         func:function(){document.write("這是一個函數func")}
};
var sObj = JSON.stringify(mObj);
document.write(sObj +"<br/>");  // ==> {"x":1,"y":{"z":[false,null,"string"]}}   對象中的方法給省略掉了 
var oObj = JSON.parse(sObj); // ==> {x:1,y:{z:[false,null,"string"]}}

對象方法

所有JS對象都從Object.prototype繼承屬性,這些繼承屬性主要是方法,因為我們對方法更加感興趣。這些方法也可以被重寫。
之前提到過很多對象方法了。這里就不具體講解了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容