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補丁。