Javascript對象學習

javascript對象

動態:可新增、刪除屬性;
但常來模擬靜態對象以及靜態類型語言中的結構體(struct),有時也做字符串的集合。
除了字符串、數字、true、false、null、undefined之外,其他的javascript都是對象。儘管字符串、數字、布爾值不是對象,行爲和不可變對象相似。

方法:
    create、set、query、delete、test、enumerate
屬性特徵:
    1.可寫:表明是否可設置改屬性的值
    2.可枚舉:表明是否可以通過for/in循環返回該屬性
    3.可配置:表明是否可以刪除或修改該屬性
  注:ECMAScript5之前,代碼給對象創建的所有屬性都是可枚舉的。之後有改變

對象特性:
    1.對象的原型(protype)指向另一個對象,本對象的屬性繼承與它的原型對象
    2.對象的類(class)是一個表示對象類型的字符串
    3.對象的擴展標記(exensible flag)指明瞭是否可以向該對象添加新屬性

三類對象和兩類屬性:
    1.內置對象(native object):ECMAScript規範定義的對象或類。例如:數組、函數、日期、正則表達式
    2.宿主對象(host object):javascript解釋器鎖嵌入的宿主環境,例如:web瀏覽器定義的。網頁結果中的htmlelement都是宿主對象。宿主環境定義的方法都可以看做普通javascript的函數對象,那麼宿主對象也可以當做內置對象
    3.自定義對象(user-defind object):由運行的javascript代碼創建的對象
    4.自有屬性(own property):直接在對象中定義的屬性
    5.繼承屬性(inherited property):在對象的原型對象中定義的屬性

原型:

所有通過對象直接量創建的對象都具有同一個原型對象,並可以通過JavaScript代碼Object.prototype獲得對原型對象的引用。
     new Object() ---> Object.prototype
     new Array() ---> Array.prototype

Object.create()

靜態函數,不提供給某個對象調用,只需傳入所需原型對象即可
    var test = Object.create(Object.prototype); //和{}、new Object()一樣
    //通過運行繼承創建一個新對象
    function inherit(p) {
        if(p == null) throw TypeError(); //p是一個對象不能爲Null
        if(Object.create) return Object.create(p); //如果Object.create存在,則直接使用
        var t = typeof p;
        if(t != 'object' && t != 'function') throw TypeError(); //進一步檢測
        function f(){} //空構造函數
        f.prototype = p; //將其原型屬性設置爲p
        return new f(); //使用f()創建p的繼承對象
    }

屬性訪問錯誤

如果對象不存在,則試圖查詢對象的屬性就會報錯。 null和undefined值都沒有屬性

    //一種冗餘但很易懂的方法
    var len = undefined;
    if(book) {
        if(book.subtitle) len=book.subtitle.length;
    }

    //簡練語法
    var len = book && book.subtitle && book.subtitle.length;

刪除屬性

delete運算符可以刪除對象的屬性。它的操作數應當是一個屬性訪問表達式。 但是,delete只是斷開屬性和宿主對象的聯繫,而不會操作屬性中的屬性

delete運算符只能刪除自有屬性,不能刪除繼承屬性(要刪除繼承屬性,必須從定義這個屬性的原型對象刪除它,而且會影響到所有繼承自這個原型的對象)

檢測屬性

判斷某個屬性是否存在於某個對象中,可以通過in運算符、hasOwnPreperty()和propertyIsEnumerable()方法等。

對象的hasOwnProperty()方法:檢測給定的名字是否是對象的自有屬性,對於繼承屬性返回false
propertyIsEnumerable():只有檢測到是自有屬性且這個屬性的可枚舉性爲true是才返回true
in運算符
!==:判斷一個屬性是否是undefined

var o = {x:0}
o.x !== undefined; //true
o.y !== undefined; //false
o.toString !== undefined; //true

有一種場景只能使用in運算符,而不能使用上述屬性訪問的方式。 in可以區分不存在的屬性和存在但值爲undefined的屬性

var o = {x:undefined};
o.x !== undefined; //false:屬性存在,值爲undefined 此時會有問題
o.y !== undefined;
'x' in o; //true:屬性存在
'y' in o; //false
delete o.x; //刪除x
‘x’ in o; //false
//把p中可枚舉的屬性賦值到o中,並返回o。 如果有同名屬性,則覆蓋
function extend(o,p) {
    for(prop in p) {
        o[prop] = p[prop];
    }

    return o;
}

//將p中可枚舉的屬性複製到o中,並返回o。 如果o和p中有同名屬性,o中不受影響
function merge(o,p) {
    for(prop in p) {
        in(o.hasOwnProperty[prop]) continue;
        o[prop] = p[prop];
    }
    return o;
}

//如果o中的屬性再p中沒有同名屬性,則從o中刪除這個屬性
function restrict(o,p) {
    for(prop in o) {
        if(! (prop in p)) delete o[prop];
    }
    return o;
}

//如果o中的屬性在p中存在同名屬性,則從o中刪除這個屬性
function subtract(o, p) {
    for(prop in p) {
        delete o[prop];
    }
    return o;
}

//返回一個新對象,這個對象同時擁有o的屬性和p的屬性; 如果有重名,則使用p中屬性
funciton union(o, p) {
    return extend(extend({}, o), p);
}

//返回一個新對象,同時擁有o和p的屬性,像求交集。p中屬性的值被忽略
function intersection(o,p) {
    return restrict(extend({}, o), p);
}

屬性的特性

  1. 值(value)
  2. 可寫性(writable)
  3. 可枚舉性(enumerable)
  4. 可配置性(configurable)

通過調用Object.getOwnPropertyDescriptor()可以獲得某個對象特定屬性的屬性描述符

//得到自有屬性的描述符
Object.getOwnPropertyDescriptor({x:1}, 'x');
//獲得繼承屬性的特性,需要遍歷原型鏈
Object。getPrototypeOf();
//要想設置屬性的特性,或者讓新建屬性具有某種特性。
Object.definePeoperty(); //傳入要修改的對象,要創建或修改的屬性的名稱以及屬性描述符對象

var o = {};
//創建一個不可枚舉的數據屬性x,賦值爲1
Object.defineProperty(o, 'x', {
    value : 1,
    writable:true,
    enumerable:false,
    configurable:true
});

//屬性存在不可枚舉
o.x;   // 1
Object.keys(o) //[]

//對屬性x進行修改,變爲只讀
Object.defineProperty(o, 'x', {writable:false});

//試圖更改這個屬性的值
o.x = 2//操作失敗但報錯,在嚴格模式裏面會拋出類型錯誤異常
o.x == 1 //true

//配置屬性
Object.defineProperty(o, 'x',{value:2});

//強x從數據屬性修改爲存取器屬性
Object.defineProperty(o, 'x', {get:function(){return 0;}});

Object.defineProperty()的屬性描述符對象不必包含所有4個特性。
對於新建屬性:默認特性值是false或undefined。
對於修改已有屬性:默認的特性值沒有做任何修改

如果同時修改多個屬性,則使用Object.defineProperties();
參數:
1. 要修改的對象
2. 映射表,包含要新建或修改的屬性的名稱,以及他們的屬性描述符

var p = Object.defineProperties({}, {
    x:{value:1, writable:true, enumerable:true, configurable:true},
    y:{value:1, writable:true, enumerable:true, configurable:true},
    r:{
        get:function() {return Math.sqrt(this.x*this.x + this.y*this.y)},
        enumerable:true,
        configurable:true
    }
});

原型屬性、類屬性、可擴展性、序列化對象

原型屬性

//ECMAScript5:傳遞對象,可獲取對象的原型
Object.getPrototypeOf()

//ECMAScript3
o.constructor.prototype檢測一個對象的原型

類屬性

function classof(o) {
    if(o === null) return 'Null';
    if(o === undefined) return 'Undefined';
    return Object.prototype.toString.call(o).slice(8, -1);
}

解析:
      1. object.prototype:object的原型對象,代表繼承關係
      2. toString:方法名
      3. call(o):返回數據的類型
      4. 獲取裏面的值,兩個參數截取:包前不包後,負數依然是包前不包後,但是是代表從結尾計數的。

//demo
var p = {x:1};
var o = Object.create(p);
p.isPrototypeOf(o) //true:o繼承與p
Object.prototype.isPrototype(o) //true,p繼承與Object.prototype

可擴展性

Object.esExtensible(); //判斷該對象是否可擴展
Object.preventExtensions(); //對象會變成不可擴展的。 改方法只會影響對象本身的可擴展性。如果給一個不可擴展的對象的原型添加屬性,這個不可擴展的對象同樣會繼承這些新屬性
Object.seal()

序列化對象

指:將對象的狀態轉換爲字符串,也可以將字符串還原爲對象

JSON.stringify() //序列化
JSON.parse() //還原對象

注意:
1. 支持對象、數組、字符串、無窮大數字、true、false和null
2. NaN、Infinity和-Infinity序列化結果依然是null
3. 日期對象序列化的結果是:ISO格式的日期字符串,但JSON.parse()依然保留他們的字符串形態,而不會還原成日期對象
4. 函數、RegExp、Error對象不支持
5. JSON.stringify() 只能序列化對象可枚舉的自有屬性,對於一個不能序列化的屬性來說,在序列化後的輸出字符串會忽略該屬性

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章