Object.defineProperty 方法

Object.defineProperty是es5中新增加的屬性描述符。在它出現之前你可能會經常有一些疑問,比如for in 循環爲何不能遍歷出函數的arguments、length、name等屬性名,delete window.a 爲何返回false, 等你學完這個api,這些現象便都能夠得到解釋。

Object.defineProperty 一共涉及6個可配置項:

    writable:	是否可重寫

    value:  	當前值

    get:    	 讀取時內部調用的函數

	set:        寫入時內部調用的函數
	
	enumerable: 	是否可以遍歷

	configurable: 	是否可再次修改配置項

我們先試圖定義一個簡單的對象如下:

var obj = {x:1}

看上去非常簡單的一句代碼,但它的定義細節比我們看到的要複雜的多,上邊這句代碼可以轉換爲es5的以下定義:

	var obj = Object.create(
		Object.prototype,{
			x: {
			 value:1,
			 writable:true,
			 enumerable: true,
			 configurable: true
			}
		 }
	)

實際上在es3中也有 [[ReadOnly]] 、 [[DontEnum]]、 [[DontDelete]] 這樣的數據屬性,對應了es5 中的訪問器屬性 [[writable]] 、 [[Enumerable]] 、[[Configurable]]

下面來看下Object.defineProperty的具體用法:

Object.defineProperty方法有三個參數,第一個參數爲要定義或修改的對象-object。第二個參數爲對象的屬性名-string, 第三個參數爲配置項。

var obj ={};

Object.defineProperty(obj,"a",{
    value:12,
    writable:true,
    enumerable:true,
    configurable:true
})

console.log(obj.a); // 12

obj.a = 'abc';

console.log(obj.a); // abc

for(var i in obj)
console.log(i); // a

對象默認是可修改可遍歷的,修改對象爲不可寫,它的屬性值便不會被改變,類似於我們用const定義一個常量。 定義爲不可遍歷,那麼它對應的那個屬性便無法被遍歷,這就可以解釋我們開頭講到的爲什麼無法遍歷函數的arguments、length、name等屬性名。


var obj ={};

Object.defineProperty(obj,"a",{
    value:100,
    writable:false,
    enumerable:false,
    configurable:true
})

console.log(obj.a);// 100

obj.a = "ccc";    // 不會報錯,但沒法修改值

console.log(obj.a); // 100

for(var key in obj)  // 不會被執行,因爲不可遍歷
console.log(key);

configurable默認是false,屬性值不可修改或刪除

var obj ={};

var obj = Object.defineProperty({},"a",{
    value:"aaa"
})

delete obj.a;  //  不會報錯,但此屬性不會被刪除

console.log(obj.a);  // aaa

obj.a = 'bbb';	

console.log(obj.a); // aaa

重頭戲! get和set的讀寫監聽:


var obj ={};

Object.defineProperty(obj,"b",{
    set:function(a){
        console.log("正在進行賦值"+a);
    },
    get:function(){
        return "aaa"
    }
})

obj.b="bbb"; // 正在進行賦值bbb
console.log(obj.b); // aaa


興許你會覺得上邊的這段代碼很簡單,但是這個get和set的api其實異常強大。時下比較流程的mvvm的框架都是基於Object.defineProperty這個api進行封裝的,尤其是set方法的監聽使用使得前端產生了數據驅動的思想。但是由於Object.defineProperty這個api在IE8中有bug,所以只能用於IE9+,所以相應的市面流行的React 、vue等框架也只能兼容到IE9+ 。

Object.defineProperty這個api雖然強大,但同樣存在着一些問題。除了我們上邊提到的瀏覽器兼容性,它在各瀏覽器的實現也略有差異。另外當Object.prototype被污染時,使用Object.defineProperty很容易程序崩潰,這種情況在各大瀏覽器均會出現。因此在計劃使用這個api封裝自己的框架之前最好還是更加深入的學習瞭解一下,收集一些專業的hack補丁。

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