關於javascript中defineProperty的學習

語法

Object.defineProperty(obj, prop, descriptor)

參數

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

返回值

    被傳遞給函數的對象。app

 

使用說明:函數

咱們通常給一個對象建立一個新的屬性時,大部分採用的都是以下方式:this

var obj = {}; obj.key = "Hello"

可是這種建立方式的屬性,其值可被修改,可被遍歷等等。 若是想建立隱藏屬性(使用for in 沒法遍歷出來)spa

或者想建立一個只讀屬性(不可寫入),使用這種方式就不可取了。在ES6中,有一個叫作Symbol類型的東西prototype

這個東西能夠人爲的定義它是否可寫,可枚舉,可重配置等等,而定義這個Symbol的方法則是Object對象的 definePropertycode

這裏能夠將Symbol理解爲帶特殊技能的屬性。 咱們能夠爲一個對象,使用defineProperty方法來定義一個帶紅藍buff的屬性對象

 

先來講說屬性描述符,由名稱可知是用來描述一個屬性具備什麼特色用的,屬性描述符分爲兩類: 數據描述符存取描述符blog

數據描述符表示一個具備值的屬性,該值可能只讀,可能可寫繼承

存儲描述符表示一個具備對數據進行存取操做的屬性。ip

一個屬性只能爲以上兩種類別中的一個,不能同時是二者

 

下面是一些上面兩個描述符可選的鍵值:

configurable:  是否容許改變描述符,是否容許刪除屬性,默認false

enumerable:   是否容許被枚舉(for in), 默認false

writeable:   是否可寫,默認false

value:    設定數據描述符的value值,默認是undefine

get:     設定存儲描述符的getter方法,默認undefine

set:     設定存儲描述符的setter方法,默認undefine

 

注意: configurable enumerable 這兩個描述鍵值 是數據描述符 與 存儲描述符 共有的

writeable 和 value 是數據描述符獨有的, 而set 和 get方法是存儲描述符獨有的,另外

這些選項不必定是自身的屬性,也須要考慮繼承,爲確保留有默認值,須要凍結以前的

Object.prototype,或者將__proto__屬性指向null

 

說了那麼多概念性的東西,下面來實戰練習一下吧

任務一: 建立一個帶有隻讀屬性的對象

var o = {};

Object.defineProperty(o, "myName", {
   value: "孫悟空",
   writeable: false        //不容許寫,只讀的
});

document.write(o.myName);        //孫悟空

//嘗試改變屬性

o.myName = "豬八戒";              //這裏不會報錯,可是會拋出readonly
document.write(o.myName);        //孫悟空

 

任務二: 建立一個帶有"隱藏"屬性的對象

var o = {};

Object.defineProperty(o, "myName", {
   value: "孫悟空",
   enumerable: false                   //不容許被枚舉出來
});


//經過普通方式建立其餘屬性
o.myAge = 33;
o.myAddress = "China";

//枚舉對象全部變量
for(var i in o){
    document.write(i +":"+ o[i] + "<br>");
}

//輸出結果:
//myAge: 33
//myAddress: China

//雖然沒法遍歷出來,可是依然是能夠訪問的
document.write(o.myName);            //孫悟空

 

任務三:建立一個帶有存儲描述符的屬性對象

var p;              //稍後使用存儲描述符對他進行讀寫操做
var o = {};

Object.defineProperty(o, "b", {   //屬性名爲b
        get: function(){
             return p;                //取全局變量
        },

        set: function(value){
             p = value;              //寫全局變量
        },

        enumerable: true,        //可遍歷
        configurable: true         //可修改
});

o.b = 38;             //看起來像是直接賦值,實際上是調用了set方法賦值

document.write(p);   //38, 由於get方法讀寫的對象是全局變量
    

存儲描述符,給人感受像是對 對象的屬性進行讀寫操做,但其實背後多是對其餘變量的讀寫

操做,由於能夠人爲的定義讀寫操做執行的函數 set/get ,因此咱們就能夠實現讀寫時實現本身

想要的功能,好比數據類型判斷等等,若是對存儲描述符仍是不太理解,能夠看看下面兩段代碼

實現一個自存檔的屬性

function Archiver() {
  var temperature = null;
  var archive = [];

  Object.defineProperty(this, 'temperature', {
    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';

// 'I alway return this string,whatever you have assigned'
console.log(instance.myproperty);
// 'this is my name string'
console.log(instance.myname);

對於configurable的效果,你們可能還有疑問,能夠閱讀下面這段代碼,本身動手試試

var o = {};
Object.defineProperty(o, "a", { get : function(){return 1;}, 
                                configurable : false } );

// throws a TypeError
Object.defineProperty(o, "a", {configurable : true}); 
// throws a TypeError
Object.defineProperty(o, "a", {enumerable : true}); 
// throws a TypeError (set was undefined previously) 
Object.defineProperty(o, "a", {set : function(){}}); 
// throws a TypeError (even though the new get does exactly the same thing) 
Object.defineProperty(o, "a", {get : function(){return 1;}});
// throws a TypeError
Object.defineProperty(o, "a", {value : 12});

console.log(o.a); // logs 1
delete o.a; // Nothing happens
console.log(o.a); // logs 1
相關文章
相關標籤/搜索