JS的數據屬性和訪問器屬性

 

ECMA-262第5版在定義只有內部才用的特性(attribute)時,描述了屬性(property)的各種特徵。ECMA-262定義這些特性是爲了實現javascript引擎用的,因此在javascript中不能直接訪問它們。爲了表示特性時內部值,該規範把它們放在了兩對方括號中,例如[[Enumerable]]。

數據屬性

數據屬性包含一個數據值的位置,在這個位置可以讀取和寫入值。數據屬性有4個描述其行爲的特性

類別

Value

包含這個屬性的數據值。讀取屬性值的時候,從這個位置讀取,寫入值得時候,把新值保存在這個位置。這個特性得默認值爲undefined

Configurable

表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改爲訪問器屬性。直接在對象上定義的屬性,它們的這個特性默認值爲true

Enumerable

表示能否通過for-in循環返回屬性,直接在對象上定義的屬性,它們的這個特性默認值爲true

Writable

表示能否修改屬性的值,直接在對象上定義的屬性,它們的這個特性默認值爲true

修改

要修改默認的特性,必須使用ES5的Object.defineProperty()方法

// 使用方式
Object.defineProperty( obj, prop, descriptor)
obj:需要定義屬性的對象。
prop:需定義或修改的屬性的名字。
descriptor:一個包含設置特性的對象
// 例子
var person = {name: "percy"};
Object.defineProperty(person,"name",{
  writable: false
});

讀取

通過,Object.getOwnPropertyDescriptor()方法獲取指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不需要從原型鏈上進行查找的屬性)

var girl = {name: "zyj"};
console.log(Object.getOwnPropertyDescriptor(girl,"name"));
// Object {value: "zyj", writable: true, enumerable: true, configurable: true}

注意⚠️

  • 直接在對象上定義的屬性,它們的[[Configurable]]、[[Enumerable]]、[[Writable]]特性都被設置爲true,[[Value]]特性被設置爲了指定的值.

訪問器屬性

訪問器屬性不包含數據值,它們包含一對getter和setter函數(這兩個函數都不是必須的)。在讀取訪問器屬性時會調用getter函數,這個函數會負責返回有效的值,在寫入訪問器屬性時,會調用setter函數並傳入新值。這個函數負責決定如何處理數據。訪問器屬性有如下4個特性

類別

Configurable

表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改爲數據屬性。直接在對象上定義的屬性,這個特性的默認值爲true

Enumerable

表示能否通過for-in循環返回屬性。直接在對象上定義的屬性,這個特性的默認值爲true

Get

在讀取屬性時調用的函數。默認值爲undefined

Set

在寫入屬性時調用的函數。默認值爲undefined

定義

訪問器屬性不能直接定義,必須使用Object.defineProperty()定義單個或者Object.defineProperties()來定義

定義單個。注意⚠️:用Object.defineProperty()定義的訪問器屬性,其configurable和enumerable默認爲false。

var book = {
    year : 2004,
    edition : 1
};
Object.defineProperty(book,"year",{ 
    get : function () {
        alert(this.year);
    },
    set : function (newValue) {
        if (newValue > 2004) {
            this.year = newValue;
            this.edition += newValue - 2004;
        }
    }
});
book.year;      // 彈出窗口,顯示 2004
book.year = 2005;
console.log(book.edition);   // 2

定義多個

var obj = {};
Object.defineProperties(obj, {
  "property1": {
    value: true,
    writable: true
  },
  "property2": {
    value: "Hello",
    writable: false
  }
});

讀取

通過,Object.getOwnPropertyDescriptor()方法獲取指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不需要從原型鏈上進行查找的屬性)

var descriptor = Object.getOwnPropertyDescriptor(girl,"age");
console.log(descriptor.value);         // 22
console.log(descriptor.configurable);  // false
console.log(descriptor.writable);      // true
console.log(descriptor.get);           // undefined
console.log(descriptor.set);           // undefined

注意⚠️

用Object.defineProperty()定義的訪問器屬性,其configurable和enumerable默認爲false。

數據屬性和訪問器屬性互相轉化

數據屬性 -> 訪問器屬性

屬性的特性只能是訪問器描述符和數據描述符中的一種,給已有的數據屬性加get或set轉換爲訪問器屬性時,其屬性的value、writable就會被廢棄。

// 設置get和set其中任意一個即可轉換爲訪問器屬性
Object.defineProperty(person, "year", {
    get: function() {
        return this._year;    
    },
    set: function(value) {
        this._year= value;
    }
})
var descriptor = Object.getOwnPropertyDescriptor(person, 'year');
console.log(descriptor);    // {get: ƒ, set: ƒ, enumerable: true, configurable: true}

訪問器屬性 -> 數據屬性

將訪問器屬性轉換爲數據屬性,只需要給現有訪問器屬性設置value或writable這兩個屬性描述符中的任意一個即可,其原有的get和set就會被廢棄,從而轉換爲數據屬性。

注意⚠️:可以在訪問器屬性和數據屬性間相互轉化的屬性其configurable特性值必須爲true。configurable爲false,則不可以將其轉換爲數據屬性。

Object.defineProperty(person, "job", {
    configurable: true,
    enumerable: true,
    get: function() {
        return this._job;
    },
    set: function(value) {
        this._job = value;
    }
});
// 設置value和writable其中任意一個即可轉換爲數據屬性        
Object.defineProperty(person, "job", {
    value: 'worker',
    writable: true
});
var descriptor = Object.getOwnPropertyDescriptor(person, 'job');
console.log(descriptor);    // {value: "worker", writable: true, enumerable: true, configurable: true}

擴展:如何定義對象

定義對象一共有如下四種方式

  • 使用語法結構創建的對象
  • 使用構造器創建的對象
  • 使用 Object.create 創建的對象
  • 使用 class 關鍵字創建的對象

下面我們分別來給個例子🌰

使用語法結構創建對象

var o = {a: 1};

使用構造器創建對象

function Graph() {
  this.vertices = [];
  this.edges = [];
}
var g = new Graph();

使用 Object.create 創建對象

var a = {a: 1}; 
var b = Object.create(a);

使用 class 關鍵字創建的對象

class Polygon {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}
let polygon = new Polygon();

參考

MDN文檔

https://blog.csdn.net/weixin_43936704/article/details/103930693https://www.cnblogs.com/he-ming-min/p/11011402.htmlhttps://www.cnblogs.com/absolute-child/p/7188417.html

https://www.cnblogs.com/shiningly/p/9482283.html?utm_source=debugrun&utm_medium=referral

 

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