關於Object.defineProperty()理解與使用

該方法允許精確添加或修改對象的屬性。通過賦值操作添加的普通屬性是可枚舉的,能夠在屬性枚舉期間呈現出來(for…in 或 Object.keys 方法), 這些屬性的值可以被改變,也可以被刪除。這個方法允許修改默認的額外選項(或配置)。默認情況下,使用 Object.defineProperty() 添加的屬性值是不可修改的。
Object.defineProperty(obj, prop, descriptor):

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

屬性描述符

對象裏目前存在的屬性描述符有兩種主要形式:數據描述符存取描述符。數據描述符是一個具有值的屬性,該值可能是可寫的,也可能不是可寫的。存取描述符是由getter-setter函數對描述的屬性。描述符必須是這兩種形式之一;不能同時是兩者。

  • 數據描述符存取描述符均具有以下可選鍵值(默認值是在使用Object.defineProperty()定義屬性的情況下):
    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。當屬性值修改時,觸發執行該方法。該方法將接受唯一參數,即該屬性新的參數值。默認爲 undefined

此外,所有的屬性描述符都是非必須的,但是 descriptor 這個字段是必須的,如果不進行任何配置,你可以這樣:

var obj = Object.defineProperty({}, "num", {});
console.log(obj.num); // undefined

描述符可同時具有的鍵值:
描述符屬性
如果一個描述符不具有value,writable,get 和 set 任意一個關鍵字,那麼它將被認爲是一個數據描述符。如果一個描述符同時有(value或writable)和(get或set)關鍵字,將會產生一個異常。

默認值總結:
屬性默認值

示例:

var o={};//創建一個新對象
Object.defineProperty(o,"a",{
    //該屬性對應的值。可以是任何有效的 JavaScript 值(數值,對象,函數等)。默認爲 undefined
    value:37,
    // 僅當僅當該屬性的writable爲 true 時,該屬性才能被賦值運算符改變。默認爲 false
    writable:true,
    //僅當該屬性的 enumerable 爲 true 時,該屬性才能夠出現在對象的枚舉屬性中。默認爲 false
    enumerable:true,
    // 僅當該屬性的 configurable 爲 true 時,該屬性才能夠被改變,也能夠被刪除。默認爲 false
    configurable:true
});
// 對象o擁有了屬性a,值爲37

var bValue;
Object.defineProperty(o,"b",{
    get:function () { return bValue; },
    set:function (v) { bValue=v; },
    enumerable:true,
    configurable:true
});
o.b=45;

數據和視圖聯動:

給對象o定義新的屬性b,並且定義屬性b的get和set方法,當o.b的時候會調用b屬性的get方法,給b屬性賦值的時候,會調用set方法,這就是修改數據的時候,視圖會自動更新的關鍵。
前端獲取數據後,需要根據數據操作dom,視圖變化後,需要修改不少代碼,有沒有方法將數據和dom操作隔離,看一個例子,顯示用戶信息的html模版。

<div>
    <p>你好,<span id='nickName'></span></p>
    <div id="introduce"></div>
</div> 
//視圖控制器
var userInfo = {};
Object.defineProperty(userInfo, "nickName", {
    get: function(){
        return document.getElementById('nickName').innerHTML;
    },
    set: function(nick){
        document.getElementById('nickName').innerHTML = nick;
    }
});
Object.defineProperty(userInfo, "introduce", {
    get: function(){
        return document.getElementById('introduce').innerHTML;
    },
    set: function(introduce){
        document.getElementById('introduce').innerHTML = introduce;
    }
});

//數據
//todo 獲取用戶信息的代碼
....

userInfo.nickName = "xxx";
userInfo.introduce = "我是xxx,我來自雲南,..."

示例2

傳統的做法:

<span id="container">1</span>
<button id="button">點擊加 1</button>
document.getElementById('button').addEventListener("click", function(){
    var container = document.getElementById("container");
    container.innerHTML = Number(container.innerHTML) + 1;
});

使用defineProperty:

var obj = {
    value: 1
}
//存儲 obj.value 的值的變量
var value = 1;
Object.defineProperty(obj, "value", {
    get: function() {
        return value;
    },
    set: function(newValue) {
        value = newValue;
        document.getElementById('container').innerHTML = newValue;
    }
});
document.getElementById('button').addEventListener("click", function() {
    obj.value += 1;
});

現在的寫法,我們還需要單獨聲明一個變量value 存儲 obj.value 的值,因爲如果你在 set 中直接 obj.value = newValue 就會陷入無限的循環中。此外,我們可能需要監控很多屬性值的改變,要是一個一個寫,也很累吶,所以我們簡單寫個 watch 函數。

var obj = {
    value: 1
}
watch(obj, "value", function(newvalue){
    document.getElementById('container').innerHTML = newvalue;
})
document.getElementById('button').addEventListener("click", function(){
    obj.value += 1
});

watch 函數:

(function(){
    var root = this;
    function watch(obj, name, func){
       //存儲value的變量
        var value = obj[name];
        Object.defineProperty(obj, name, {
            get: function() {
                return value;
            },
            set: function(newValue) {
                value = newValue;
                func(value)
            }
        });
        if (value) obj[name] = value
    }
    this.watch = watch;
})()

內容來源及參考博文:
深入淺出Object.defineProperty() - 簡書
Object.defineProperty() - [MDN]
Object.defineProperty()方法詳解 - 蔣金柱 - 博客園
Object.defineProperty - 樂樂曹 - 簡書

發佈了12 篇原創文章 · 獲贊 4 · 訪問量 1856
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章