淺談js對象之數據屬性、訪問器屬性、Object.defineProperty方法


一、對象

  這個不用多說,常見的幾種創建對象的方法有:

  1.通過構造函數創建對象,如下所示:

 function Person(){

        }
 var person = new Person();

 

  2.通過Object創建簡單對象,例如:

 var obj = new Object();

  3.通過字面量創建對象。

 var obj = {};

  常用的一般是第一種和第三種方法。

二、屬性類型

  javascript中有兩種屬性:數據屬性和訪問器屬性,確切的說這兩種特性是用來描述對象屬性的各種特征,比如說這個對象屬性的值能否被改變,因為這些特性是內部值,而javascript又不能直接訪問,所以在規范中把他們放在了兩對兒化括號中,例如[[Enumerable]]。下面 來看看這兩種具體的內部屬性。

  1.數據屬性

   數據屬性包含一個數據值。在這個位置可以讀取和寫入值,

     [[Configurable]]:表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,能否把屬性修改為訪問器屬性(這個后面會說),默認為true;

     [[Enumerable]]:用來修飾對象屬性的枚舉特性,表示能否通過用for in循環返回屬性,默認為true;

     [[Writable]]:用來修飾對象屬性值的可寫特性,默認為true;

   [[Value]]:包含這個屬性的數據值,訪問器屬性里面是沒有這個特性的。默認為undefined;比如var person = {name:'lili'},這里設置了一個名叫name的屬性,它的值是"lili", [[Value]]特性將被設置為"lili",其余的是三個特性都是默認值true。

  下面就用具體的實例來理解上面的特性。首先這里要先談的是Object.defineProperty()方法,這個方法接收三個參數:屬性所在的對象、屬性的名字、和一個描述符對象(也就是上面的四個數據屬性,用來描述對象屬性的特性),這里要注意了,采用Object.defineProperty方法創建屬性時候,數據屬性[[configurable]]、[[writable]]、[[enumerable]]默認為false,這要和字面量直接聲明屬性時默認值相反但是如果只是用Object.defineProperty改變原來已有屬性的值則沒有此限制,具體看下面例子:

     var person = {};
    Object.defineProperty(person,'name',{ //創建name屬性 value:'lili', }); console.log(person.name); //lili person.name = 'shasha'; //writable默認是false 不可改動屬性值 console.log(person.name); //lili

 

  修改writable的值為true可以看到,person.name的值打印出來是'shasha';

     var person = {};
    Object.defineProperty(person,'name',{//創建name屬性
            writable:true,
            value:'lili',
        });
        console.log(person.name); //lili
        person.name = 'shasha'; //writable設置為true, 屬性值被重寫
        console.log(person.name); //shasha

 但是當person里面有屬性,采用Object.defineProperty方法只是修改特性和值時,默認值都為true,具體請看下面示例:

       var person = {age:22};
        Object.defineProperty(person,'age',{  //重新定義修改age屬性
            value:33,
        });
        person.age = 66;
        console.log(person.age); //66  說明writable此時為true,

  設置[[enumrable]]特性的規則跟[[writable]]相同,為true時才能用for in 循環遍歷出屬性。下面來重點看看[[Configurable]]特性的作用,例子如下:

      var person = {};
        Object.defineProperty(person,'name',{
            configurable:false,
            value:'lili',
        });
        console.log(person.name); //lili
        delete person.name;
        console.log(person.name); //lili

  把configurable設置為false,表示不能刪除對象屬性,對這個這個屬性調用delete方法,非嚴格模式下什么也不會發生,嚴格模式下則會拋出錯誤,而且一旦把屬性從configurable設置為false,以后就不能把它設置為true,此時在調用Object.defineProperty方法修改除writable、value之外的特性,都會導致錯誤,看下面例子:

   var person = {};
        Object.defineProperty(person, 'name', {
            configurable: false,
            enumerable: true,
            writable: true,
            value: 'lili',
        });
        Object.defineProperty(person, 'name', {
            // configurable: true,  //會報錯額!
            // enumerable: false,  //會報錯的!
            writable: false,
            value: 'tangtang',
        });
        person.name = 'wangdachui';
        console.log(person.name);//tangtang

  2.訪問器屬性

  訪問器屬性不包括數據值,它包含一對getter和setter函數,在讀取訪問器屬性時,會調用getter函數,這個函數負責返回有效的值;在寫入訪問器屬性時,會調用setter函數並傳入新值,訪問器屬性有如下四個特性:

   [[Configurable]]:表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,能否把屬性修改為數據屬性(這個后面會說),默認為true;

   [[Enumerable]]:用來修飾對象屬性的枚舉特性,表示能否通過用for in循環返回屬性,默認為true;

   [[Get]]:在讀取屬性時候調用的函數,默認為undeifne;

   [[Set]]:在寫入屬性時候調用的函數,默認為undeifne;

  訪問器屬性不能直接定義,必須使用Object.defineProperty()來定義。請看下面的例子。

      var book = {
            _year: 2018,
            edition: 1,
        };
        Object.defineProperty(book, 'year', {
            get: function () {
                alert('通過對象方法訪問 哈哈!');
                return this._year;
            },
            set: function (newValue) {
                if (newValue > 2004) {
                    this._year = newValue;
                    this.edition += newValue - 2004;
                    alert(this.edition);
                }
            }
        });
        console.log(book.year) //通過對象方法訪問 get函數里面alert出對應信息;
        book.year = 2005;
        console.log(book.edition); //2

  以上例子中,book對象有兩個默認屬性:_year 和 edition ,其中_year前面加了下划線,用於表示只能通過對象方法去訪問這個屬性,即通過get方法返回屬性值。如果直接訪問book.edition的值,則不會調用get方法返回。book.year=2005即是修改book的year屬性值,會調用set方法,參數newValue就是設置的2005這個值,在上面例子中set函數里還改變了屬性edition的值。

3.定義多個屬性

  采用Object.defineProperties我們也可以為一個對象定義多個屬性,這個方法有兩個參數:第一個要定義屬性的對象,第二個也是對象,表示要添加的多個屬性和其對應的屬性描述符,具體怎么添加呢,請看下面的例子:

      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;
                    }
                }
            }
        });

  以上代碼在book對象上定義了兩個數據屬性(_year和edition)和一個訪問器屬性(year)。

  4.讀取屬性的特性

  上面我們一直是在討論如何設置屬性的描述特性,那么對於數據屬性和訪問器屬性里面的具體特性我們怎么讀取呢?這里介紹另一個Object的方法:getOwnPropertyDescriptor方法,該方法接收兩個參數:屬性所在的對象和要讀取其描述符的屬性名稱,它的返回是一個對象,來我們來看看具體的實例:

      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;
                    }
                }
            }
        });
        book.year = 2005;
        console.log(book.edition); //2
        var descriptor1 = Object.getOwnPropertyDescriptor(book, '_year');
        console.log(descriptor1.value); //2005
        console.log(descriptor1.configurable);//false
        console.log(typeof descriptor1.get); //undefine
        var descriptor2 = Object.getOwnPropertyDescriptor(book, 'year');
        console.log(descriptor2.value); //2005
        console.log(descriptor2.configurable);//false
        console.log(typeof descriptor2.get); //function;

 

 

  

  

  

  

  

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM