JavaScript 數據屬性和訪問器屬性

  在JavaScript中對象被定義爲"無序屬性的集合,其屬性能夠包含基本值、對象或函數。"通俗點講,咱們能夠把對象理解爲一組一組的名值對,其中值能夠是數據或函數。函數

  建立自定義對象一般有兩種方法,第一種就是建立一個Object的實例,而後再爲其添加屬性和方法,例如:this

var person = new Object();
person.name = "Scott";
person.age = 24;
person.sayName = function(){
    alert(person.name);
}

  第二種方法即對象字面量法,通常推薦使用這種方法建立對象,例如:指針

var person = {
    name: "Scott",
    age: 24,
    sayName: function(){
         alert(this.name);  
    }
}

  屬性類型

  JavaScript中定義了兩種不一樣的屬性:數據屬性和訪問器屬性。數據屬性通常用於存儲數據數值,而訪問器屬性通常進行get/set操做,不能直接存儲數據數值。在ES5中,咱們爲了描述屬性(property)的各類特徵,定義了特性(attribute)。在JavaScript中不能直接訪問特性,咱們把它放在兩對方括號中,例如[[Enumerable]]。對象

  • 數據屬性

  數據屬性主要有四個特性描述其行爲:ip

  1. [[Configurable]]:默認爲true。表示可否經過delete刪除屬性從而從新定義屬性,可否修改屬性特性,或者可否把屬性修改成訪問器屬性;
  2. [[Enumerable]]:默認爲true。表示可否經過for-in循環返回屬性;
  3. [[Writable]]:默認爲true。表示可否修改屬性的值。
  4. [[Value]]:默認值爲undefined。表示包含屬性的數據值。讀寫屬性值都從這個位置進行。

  對於上面直接在person對象上定義的屬性,它們的[[Configurable]]、[[Enumerable]]、[[Writable]]特性都被默認設置爲true,而[[Value]]特性被設置爲特定值。若是想要修改屬性默認的特性,可使用ES5提供的Object.defineProperty()方法,這個方法接收三個參數:屬性所在對象、屬性的名字和一個描述符對象。描述符對象只能包含上述四個特性的一個或多個。例子以下:get

var person = {
    name: "Scott"
}
Object.defineProperty(person,"name",{
    writable:false;
})

console.log(person.name);   //"Scott"
person.name = "Evan";
console.log(person.name);   //"Scott"

  將person對象name屬性的特性writable設置爲false,此屬性的值爲不可修改的,所以對該屬性的複製操做會直接忽略。it

var person = {
    name: "Scott"
}
Object.defineProperty(person,"name",{
    configurable:false;
})

console.log(person.name);   //"Scott"
delete person.name;
console.log(person.name);   //"Scott"

  能夠看到,當把name屬性的特性值configurable設置爲false以後,就表示不能從對象中刪除屬性。但須要注意的是,當把屬性定義爲不可配置以後,就不能把它變回可配置的了。此時修改除writable以外的其它特性都會報錯,例如:io

var person = {
    name: "Scott"
}
Object.defineProperty(person,"name",{
    configurable:false;
})
Object.defineProperty(person,"name",{
    configurable:true;    //此處會拋出錯誤
})

  也就是說,在把configurable特性修改成false以後,再修改其它特性就會有限制存在。console

  • 訪問器屬性

  訪問器屬性不包含數據值。它包含一對getter和setter函數。當讀取訪問器屬性時,會調用getter函數並返回有效值;當寫入訪問器屬性時,會調用setter函數並傳入新值,setter函數負責處理數據。該屬性有四個特性:table

  1. [[Configurable]]:默認爲true。表示可否經過delete刪除屬性從而從新定義屬性,可否修改屬性特性,或者可否把屬性修改成訪問器屬性;
  2. [[Enumerable]]:默認爲true。表示可否經過for-in循環返回屬性;
  3. [[Get]]:讀取屬性時調用的函數,默認爲undefined;
  4. [[Set]]:寫入屬性時調用的函數,默認爲undefined。

  訪問器屬性不能直接定義,必須經過Object.defineProperty()函數定義,例如:

var person = {
    _name: "Scott",
    _age: 24,
    _tel: 86247
};
//name屬性爲只讀的
Object.defineProperty(person,"name",{
    get: function(){
        return this._name; 
    }
});
//age屬性爲只寫不可讀的
Object.defineProperty(person,"age",{
    set: function(p){
         this._age = p;
    }
});
//tel屬性爲可讀可寫的
Object.defineProperty(person,"tel",{
    get:function(){
         return this._tel;
    },
    set: function(p){
         this._tel = p;
    }
});
console.log(person.name);   //"Scott"
person.name = "Evan";
console.log(person.name);   //"Scott",對name屬性的修改無效
console.log(person.age);    //undefined,不可讀屬性
person.age = 25;
console.log(person._age);   //25,已經修改
console.log(person.tel);    //"86247",可讀屬性
person.tel = "13975";
console.log(person.tel);    //"13975",能夠修改

  屬性前面的下劃線表示只能經過對象方法訪問的屬性。當咱們使用person.name時實際上調用的是name屬性的getter函數,爲person.name賦值時調用的是name屬性的setter函數,這樣屬性和訪問器之間的關係就很清晰了。

  定義多個屬性

  實際上ES5爲咱們提供了爲一個對象定義多個屬性的方法,即Object.defineProperties(),該函數接收兩個參數,屬性所在的對象以及須要修改的屬性及其描述符對象組成的對象,例如把上邊的例子修改成一次性定義多個屬性,以下:

var person = {
    _name: "Scott",
    _age: 24,
    _tel: 86247
};
Object.defineProperties(person,{
    name:{
        get: function(){
           return this._name; 
        }
    },
    age:{
        set: function(p){
           this._age = p;
        }
    },
    tel:{
        get:function(){
           return this._tel;
        },
        set: function(p){
           this._tel = p;
        }
    }
});

  讀取屬性的特性

  ES5提供了Object.getOwnPropertyDescripter()方法來獲取給定屬性的描述符。該方法接收兩個參數:屬性所在的對象和要讀取其描述符的屬性名稱。結果會返回一個對象,若是是訪問器屬性,返回的對象有configuable、enumerable、get和set;若是是數據屬性,這個返回對象的屬性包括configuable、enumerable、writable和value。對於上面的例如,使用以下:

var person = {
    _name: "Scott",
    _age: 24,
    _tel: 86247
};
Object.defineProperties(person,{
    name:{
        get: function(){
           return this._name; 
        }
    },
    age:{
        set: function(p){
           this._age = p;
        }
    },
    tel:{
        get:function(){
           return this._tel;
        },
        set: function(p){
           this._tel = p;
        }
    }
});
var descripter = Object.getOwnPropertyDescripter(person,"tel");
console.log(descripter.value);   //undefined
console.log(descripter.enumerable);   //false
console.log(typeof descripter.get);   //"function"

  上面的代碼中獲取了person對象的tel屬性,因爲其是一個訪問器屬性,因此其value爲undefined,enumerable爲false,而get爲指向getter函數的一個指針。

相關文章
相關標籤/搜索