JavaScript中對象屬性描述符的使用詳解
屬性描述符是 ECMAScript 5 新增的語法,它其實就是一個內(nèi)部對象,用來描述對象的屬性的特性。
屬性描述符的結構
在 JavaScript 中,對象的屬性描述符用于描述和定義對象屬性的特性。以下是常見的屬性描述符及其作用:
configurable:表示屬性是否可以被刪除或修改特性。如果設置為 false,則不能刪除或修改該屬性的特性。默認為 true。
enumerable:表示屬性是否可以通過 for...in 循環(huán)或 Object.keys() 方法進行枚舉。如果設置為 false,則該屬性不會出現(xiàn)在枚舉中。默認為 true。
value:表示屬性的值。可以是任何有效的 JavaScript 值。
writable:表示屬性是否可以被賦值運算符修改。如果設置為 false,則該屬性的值不能被修改。默認為 true。
get:一個函數(shù),用于獲取屬性的值。當訪問該屬性時,會調(diào)用該函數(shù)并返回其返回值。
set:一個函數(shù),用于設置屬性的值。當給該屬性賦值時,會調(diào)用該函數(shù)并傳入新值作為參數(shù)。
注意這幾個屬性不是都可以一起設置。get 和 set 以及 value 和 writable 這兩組是互斥的,設置了 get 和 set 就不能設置 value 和 writable,反之設置了 value 和 writable 也就不可以設置 get 和 set。
使用示例
示例 1
下面示例演示了使用 value 讀寫屬性值的基本用法。
var obj = {} //定義空對象 Object.defineProperty(obj, 'x', {value : 100}) //添加屬性x,值為100 console.log(Object.getOwnPropertyDescriptor(obj, 'x').value) //返回100
示例 2
下面示例演示了使用 writable 屬性禁止修改屬性 x。
var obj = {}; Object.defineProperty(obj, 'x', { value : 1, // 設置屬性默認值為1 writable : false // 禁止修改屬性值 }); obj.x = 2; //修改屬性x的值 console.log(obj.x) // 1 說明修改失敗
在正常模式下,如果 writable 為 false,重寫屬性值不會報錯,但是操作失敗,而在嚴格模式下則會拋出異常。
示例 3
configurable 可以禁止修改屬性描述符,當其值為 false 時,value、writable、enumerable 和 configurable 禁止修改,同時禁止刪除屬性。
在下面示例中,當設置屬性 x 禁止修改配置后,下面操作都是不允許的,其中 obj.x=5; 若操作失敗,則后面 4 個操作方法都將拋出異常。
var obj = Object.defineProperty({}, 'x', { configurable : false // 禁止配置 }) obj.x = 5 // 試圖修改其值 console.log(obj.x); // 修改失敗,返回undefined Object.defineProperty(obj, 'x', {value : 2}) // 拋出異常 Object.defineProperty(obj, 'x', {writable: true}) // 拋出異常 Object.defineProperty(obj, 'x', {enumerable: true}) // 拋出異常 Object.defineProperty(obj, 'x', {configurable: true}) // 拋出異常
當 configurable 為 false 時,如果把 writable=true 改為 false 是允許的。只要 writable 或 configurable 有一個為 true,則 value 也允許修改。
get 和 set 函數(shù)
除了使用點語法或中括號語法訪問屬性的 value 外,還可以使用訪問器,包括 set 和 get 兩個函數(shù)。
其中,set( ) 函數(shù)可以設置 value 屬性值,而 get( ) 函數(shù)可以讀取 value 屬性值。
借助訪問器,可以為屬性的 value 設計高級功能,如禁用部分特性、設計訪問條件、利用內(nèi)部變量或?qū)傩赃M行數(shù)據(jù)處理等。
示例 1
下面示例設計對象 obj 的 x 屬性值必須為數(shù)字。為屬性 x 定義了 get 和 set 特性,obj.x 取值時,就會調(diào)用 get;賦值時,就會調(diào)用 set。
var obj = Object.create(Object.prototype, { _x : { //數(shù)據(jù)屬性 value : 1, //初始值 writable : true }, x : { //訪問器屬性 get : function () { //getter return this._x; //返回_x屬性值 }, set : function (value) { //setter if (typeof value != "number"){ throw new Error('請輸入數(shù)字'); } this._x = value; //賦值 } } }); console.log(obj.x); //1 obj.x = "2"; //拋出異常
示例 2
JavaScript 也支持一種簡寫方法。針對示例 1,通過以下方式可以快速定義屬性。
var obj = { _x : 1, // 定義 _x 屬性 get x() { return this._x }, //定義 x 屬性的 getter set x(value) { //定義 x 屬性的 setter if (typeof value != "number"){ throw new Error('請輸入數(shù)字'); } this._x = value; // 賦值 } }; console.log(obj.x); //1 obj.x = 2; console.log(obj.x); //2
取值函數(shù) get( ) 不能接收參數(shù),存值函數(shù) set( ) 只能接收一個參數(shù),用于設置屬性的值。
操作屬性描述符
屬性描述符是一個內(nèi)部對象,無法直接讀寫,可以通過下面幾個函數(shù)進行操作。
Object.getOwnPropertyDescriptor( ):可以讀出指定對象私有屬性的屬性描述符。
Object.defineProperty( ):通過定義屬性描述符來定義或修改一個屬性,然后返回修改后的描述符。
Object.defineProperties( ):可以同時定義多個屬性描述符。
Object.getOwnPropertyNames( ):獲取對象的所有私有屬性。
Object.keys( ):獲取對象的所有本地可枚舉的屬性。
propertyIsEnumerable( ):對象實例方法,直接調(diào)用,判斷指定的屬性是否可枚舉。
示例 1
在下面示例中,定義 obj 的 x 屬性允許配置特性,然后使用 Object.getOwnPropertyDescriptor( ) 函數(shù)獲取對象 obj 的 x 屬性的屬性描述符。修改屬性描述符的 set 函數(shù),重設檢測條件,允許非數(shù)值型數(shù)字賦值。
var obj = Object.create(Object.prototype, { _x: { //數(shù)據(jù)屬性 value: 1, //初始值 writable: true }, x: { //訪問器屬性 configurable: true, //允許修改配置 get: function () { //getter return this._x; //返回_x屬性值 }, set: function (value) { if (typeof value != "number") { throw new Error('請輸入數(shù)字'); } this._x = value; //賦值 } } }); var des = Object.getOwnPropertyDescriptor(obj, "x"); //獲取屬性x的屬性描述符 des.set = function (value) { //修改屬性x的屬性描述符set函數(shù) //允許非數(shù)值型的數(shù)字,也可以進行賦值 if (typeof value != "number" && isNaN(value * 1)) { throw new Error('請輸入數(shù)字'); } this._x = value; } obj = Object.defineProperty(obj, "x", des); console.log(obj.x); //1 obj.x = "2"; //把一個給數(shù)值型數(shù)字賦值給屬性x console.log(obj.x); //2
示例 2
下面示例先定義一個擴展函數(shù),使用它可以把一個對象包含的屬性以及豐富的信息復制給另一個對象。
【實現(xiàn)代碼】
function extend (toObj, fromObj) { //擴展對象 for (var property in fromObj) { //遍歷對象屬性 if (!fromObj.hasOwnProperty(property)) continue; //過濾掉繼承屬性 Object.defineProperty( //復制完整的屬性信息 toObj, //目標對象 property, //私有屬性 Object.getOwnPropertyDescriptor(fromObj, property) //獲取屬性描述符 ); } return toObj; //返回目標對象 }
【應用代碼】
var obj = {}; //新建對象 obj.x = 1; //定義對象屬性 extend(obj, { get y() { return 2} }) //定義讀取器對象 console.log(obj.y); //2
控制對象狀態(tài)
JavaScript 提供了 3 種方法,用來精確控制一個對象的讀寫狀態(tài),防止對象被改變。
- Object.preventExtensions:阻止為對象添加新的屬性。
- Object.seal:阻止為對象添加新的屬性,同時也無法刪除舊屬性。等價于屬性描述符的 configurable 屬性設為 false。注意,該方法不影響修改某個屬性的值。
- Object.freeze:阻止為一個對象添加新屬性、刪除舊屬性、修改屬性值。
同時提供了 3 個對應的輔助檢查函數(shù),簡單說明如下:
- Object.isExtensible:檢查一個對象是否允許添加新的屬性。
- Object.isSealed:檢查一個對象是否使用了 Object.seal 方法。
- Object.isFrozen:檢查一個對象是否使用了 Object.freeze 方法。
示例
下面代碼分別使用 Object.preventExtensions、Object.seal 和 Object.freeze 函數(shù)控制對象的狀態(tài),然后再使用 Object.isExtensible、Object.isSealed 和 Object.isFrozen 函數(shù)檢測對象的狀態(tài)。
var obj1 = {}; console.log(Object.isExtensible(obj1)); //true Object.preventExtensions(obj1); console.log(Object.isExtensible(obj1)); //false var obj2 = {}; console.log(Object.isSealed(obj2)); //true Object.seal(obj2); console.log(Object.isSealed(obj2)); //false var obj3 = {}; console.log(Object.isFrozen(obj3)); //true Object.freeze(obj3); console.log(Object.isFrozen(obj3)); //false
總結
這些描述符可以通過 Object.defineProperty() 方法來定義或修改對象的屬性特性。通過使用這些描述符,我們可以靈活地控制和定義對象的屬性行為,例如限制某些屬性只讀、隱藏某些不需要枚舉的屬性等。
總的來說,對象的屬性描述符提供了對對象屬性行為進行詳細控制和定義的能力,包括可配置性、可枚舉性、可寫性、獲取和設置方法等。這使得我們能夠更好地管理和操作對象中的各個屬性。
到此這篇關于JavaScript中對象屬性描述符的使用詳解的文章就介紹到這了,更多相關JavaScript屬性描述符內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
實現(xiàn)超用戶體驗 table排序javascript實現(xiàn)代碼
2009-06-06也說JavaScript中String類的replace函數(shù)
最近讀了sharpxiajun的博文《javascript筆記--String類replace函數(shù)的一些事》,感覺寫的很好,很有幫助。2011-09-09JSON.parse處理非標準Json數(shù)據(jù)出錯的解決
這篇文章主要介紹了JSON.parse處理非標準Json數(shù)據(jù)出錯的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09javascript的動態(tài)加載、緩存、更新以及復用(一)
在做OA、MIS、ERP等信息管理類的項目,經(jīng)常會遇到引用很多js文件,這就需要用到動態(tài)加載、緩存、更新以及復用等技術,下面我們來討論下2014-06-06