JavaScript Object.defineProperty()學習筆記。

屬性類型

ECMAScript中有兩種屬性:數據屬性和訪問器屬性。
數據屬性:
數據屬性包含一個數據值的位置。在這個位置能夠讀取和寫入值。數據屬性有4個描述其行爲的特性。數組

[[Configurable]]:表示可否經過delete刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成訪問器屬性。在對象上直接定義的屬性,它們的這個特性默認值爲true。
[[Enumerable]]:表示可否經過for-in循環返回屬性。在對象上直接定義的屬性,它們的這個特性默認值爲true。
[[Writable]]:表示可否修改屬性的值。在對象上直接定義的屬性,它們的這個特性默認爲true.
[[Value]]:包含這個屬性的數據值。讀取屬性值的時候,從這個位置讀;寫入屬性值的時候,把新值保存在這個位置。這個特性的默認值爲undefined。

要修改屬性默認的特性,必須使用ECMAScript5的Object.defineProperty()方法。這個方法接受三個參數:屬性所在的對象、屬性的名字和一個描述符對象。其中,描述符對象的屬性必須是:configurable、enumerable、writable和value。設置其中的一個或多個值,能夠修改對應的特性值。例如:函數

var person = {};
Obejct.defineproperty(person,'name',{
    writable:false,
    value:'Nics'
})
console.log(person.name)//Nics
person.name = 'tom';
console.log(person.name)//Nics

這個例子建立了一個明爲name的屬性,它的值是隻讀的,若是爲它指定新的值,在非嚴格模式下,賦值操做將被忽略;在嚴格模式下賦值操做將會拋出錯誤。
若是把configurable設置爲false,表示不能從對象中刪除屬性,並且一旦把屬性定義爲不可配置的,就不能再把它變爲可配置了。此時再調用Object.defineProperty()方法修改writable以外的特性都會拋出錯誤。
也就是說,能夠屢次調用Object.defineProperty()方法修改同一個屬性,但在把configurable特性設置爲false以後就會有限制了。
再調用Object.defineProperty()方法建立一個新的屬性的時候,若是不指定configurable、enumerable、writable特性的默認值都是false。
Obejct.defineProperty(obj,prop,descriptor)方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,並返回這個對象。
參數:this

obj:要在其上定義屬性的對象。
prop:要定義或修改的屬性的名稱。
descriptor:將被定義或修改的屬性描述符。

返回值:prototype

被傳遞給函數的對象。

屬性描述符:日誌

configurable:當且僅當改屬性的configurable爲true時,該屬性描述符纔可以被改變,同時該屬性也能從對應的對象上被刪除。默認爲false。
enumerable:當且僅當改屬性的enumerable爲true時,改屬性纔可以出如今對象的枚舉屬性中。默認爲false。
數據描述符同時具備如下可選鍵值:
value:該屬性對應的值。能夠是任何有效的JavaScript值(數值,對象,函數等)。默認爲undefined。
writable:當且僅當該屬性的writable爲true時,value才能被賦值運算符改變。默認爲false。
存取描述符同時具備如下可選鍵值:
get:一個給屬性提供getter的方法,若是沒有getter則爲undefined。當訪問改屬性時,該方法會被執行,方法執行時沒有參數傳入,可是會傳入this對象(因爲繼承關係,這裏的this並不必定是定義該屬性的對象)默認爲undefined。
set:一個給屬性提供setter的方法,若是沒有setter則爲undefined。當屬性值修改時,觸發執行該方法。該方法將接受惟一參數,即改屬性新的參數值。
var o = {}
//在對象中添加一個屬性與數據描述符的示例。
Obejct.defineProperty(o,'a',{
    value:37,
    writable:true,
    enumerable:true,
    configurable:true
})
//對象o擁有了屬性a,值爲37

//在對象中添加一個屬性與存取描述符的示例。
var bValue;
Obejct.defineProperyty(o,'b',{
    get:function(){
        return bValue;
    },
    set:function(newValue){
        bValue = newValue;
    },
    enumerable:true,
    configurable:true
})
o.b = 38;
//對象o擁有了屬性b,值爲38.
//數據描述符和存取描述符不能混合使用。

通常的Setters和Getters
下面的例子展現瞭如何實現一個自存檔對象。當設置temperature屬性時,archive數組會獲取日誌條目。code

function Archiver(){
    var temperatrue = null;
    var aechive = [];
    Obejct.defineProperty(this,'temperatrue',{
        get:function(){
            console.log('get!');
            return temperature;
        },
        set:function(value){
            temperature = value;
            archive.push({val:temperature})
        }
    });
    this.getArchive = function(){return archive}
}
var arc = new Archiver();
arc.temperature;//'get!';
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive();//[{val:11},{val:13}]

或:對象

var pattern = {
    get:function(){
        return 'I alway return this string,whatever you have assigned'
    },
    set:function(){
        this.myname = 'this is my name string'
    }
}
function TestDefineSetAndGet(){
    Object.defineProperty(this,'myproperty',pattern);
}
var instance = new TestDefineSetAndGet();
instance.myproperty = 'test';
console.log(instance.myproperty);
console.log(instance.myname)

若是訪問者的屬性是被繼承的,他的get和set方法會在子對象的屬性被訪問或者修改時被調用。若是這些方法用一個變量存值,該值會被全部對象共享。繼承

function myclass(){}
var value;
Obejct.defineProperty(myclass.prototype,'x',{
    get(){
        return value;
    },
    set(x){
        value = x;
    }
})
var a = new myclass();
var b = new myclass();
a.x=1;
console.log(b.x);//1

在get和set方法中,this指向某個被訪問和修改屬性的對象。ip

function myclass(){}
Obejct.defineProperty(myclass.prototype,'x',{
    get(){
        return this.stored_x;
    },
    set(x){
        this.stored_x = x;
    }
});
var a = new myclass();
var b = new myclass();
a.x=1;
console.log(b.x)//undefined

不像訪問者屬性,值屬性始終在對象自身上設置,而不是一個原型。然而,若是一個不可寫的屬性被繼承,它仍然能夠防止修改對象的屬性。get

function myclass() {
}
myclass.prototype.x = 1;
Object.defineProperty(myclass.prototype, "y", {
  writable: false,
  value: 1
});
var a = new myclass();
a.x = 2;
console.log(a.x); // 2
console.log(myclass.prototype.x); // 1
a.y = 2; // Ignored, throws in strict mode
console.log(a.y); // 1
console.log(myclass.prototype.y); // 1
相關文章
相關標籤/搜索