javascript
JavaScript Object.defineProperty()方法详解
Object.defineProperty() 方法直接在一個對象上定義一個新屬性,或者修改一個已經存在的屬性,并返回這個對象。因此,又稱為屬性攔截器。在前端中,webpack以及vue的原理都應用了這個方法。
語法
Object.defineProperty(obj, prop, descriptor)參數
- obj ?需要定義屬性的對象。
- prop ?需要定義或者修改的屬性名。
- descriptor ?需要定義或者修改的屬性的描述符。
描述
該方法允許精確添加或者修改對象的屬性。一般情況下,我們為對象添加屬性是通過賦值來創建并顯示在屬性枚舉中(for...in或者Object.keys方法),但這種添加的屬性值可以被改變,也可以被刪除。而使用Object.defineProperty()則允許改變這些額外細節的默認設置。比如,默認情況下使用Object.defineProperty()增加的屬性是不可改變的。
對象里目前存在的屬性描述符有兩種主要形式:
數據描述符和存取描述符
數據描述符是一個擁有可寫或者不可寫的屬性。存取描述符是由一對setter-getter函數功能來描述的屬性。描述符必須是兩種形式之一,不能同時是兩種。
數據描述符合存取符均具有以下可選鍵值:
- configurable ?僅當該屬性為true時,該屬性才能夠被改變,也能被刪除。默認為false。
- enumerable ? 僅當該屬性為true時,該屬性才能出現在對象的枚舉屬性中。默認為false。
- value ?該屬性對應的值。可以是任何有效的Javascript值,包括數值、對象和函數等。默認值為underfined。
- writable ?僅當該屬性為true時,該屬性才能被賦值被改變。默認為false。
- get ?一個屬性提供的getter方法。如果沒有getter則為undefined。該方法返回值作為對象屬性的賦值。默認為undefined。
- set??一個屬性提供的setter方法。如果沒有setter則為undefined。該方法將接受唯一參數,并將該參數的新值分配給該屬性。默認為undefined。
創建屬性
如果對象中不存在指定的屬性,Object.defineProperty()就創建這個屬性。當描述符中省略某些字段時,這些字段將使用它們的默認值。擁有布爾值的字段的默認值都是false。value,get和set字段的默認值為undefined。定義屬性時如果沒有get/set/value/writable,那它將被歸為數據類描述。
var o = {}; // 創建一個新對象// Example of an object property added with defineProperty with a data property descriptor Object.defineProperty(o, "a", {value : 37,writable : true,enumerable : true,configurable : true}); // 對象o擁有了屬性a,值為37// Example of an object property added with defineProperty with an accessor property descriptor var bValue; Object.defineProperty(o, "b", {get : function(){ return bValue; },set : function(newValue){ bValue = newValue; },enumerable : true,configurable : true}); o.b = 38; // 對象o擁有了屬性b,值為38// The value of o.b is now always identical to bValue, unless o.b is redefined// 數據描述符和存取描述符不能混合使用 Object.defineProperty(o, "conflict", { value: 0x9f91102, get: function() { return 0xdeadbeef; } }); // throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors修改屬性
如果屬性已經存在,Object.defineProperty()將嘗試根據描述符的值以及對象當前的配置來修改這個屬性。如果描述的configurable特性為false,那么除了writable外,其他特性都不能被修改,并且數據和存取描述符也不能相互切磋。
如果configurable為false,則其writable特性也只能為false。
如果嘗試修改該值時,那么將會出現TypeError。
Writable屬性
當屬性特性writable設置為false時,表示non-writable,屬性將不能被修改。修改一個non-writable的屬性不會改變屬性的值,同時也不會報出異常。
var o = {}; // 創建一個新對象Object.defineProperty(o, "a", { value : 37,writable : false });console.log(o.a); // 打印 37 o.a = 25; // 沒有錯誤拋出(在嚴格模式下會拋出,即使之前已經有相同的值) console.log(o.a); // 打印 37, 賦值不起作用。Enumerable 特性
屬性特性enumerable定義了對象的屬性是否可以在for...in循環和Object.keys()中枚舉。
var o = {}; Object.defineProperty(o, "a", { value : 1, enumerable:true }); Object.defineProperty(o, "b", { value : 2, enumerable:false }); Object.defineProperty(o, "c", { value : 3 }); // enumerable defaults to false o.d = 4; // 如果使用直接賦值的方式創建對象的屬性,則這個屬性的enumerable為truefor (var i in o) { console.log(i); } // 打印 'a' 和 'd' (in undefined order)Object.keys(o); // ["a", "d"]o.propertyIsEnumerable('a'); // true o.propertyIsEnumerable('b'); // false o.propertyIsEnumerable('c'); // falseConfigurable特性
configurable特性表示對象的屬性是否可以被刪除,以及除writable特性外的其他特性是否可以被修改。
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添加多個屬性和默認值
考慮特性被賦予的默認特性值非常重要,通常,使用點運算符和Object.defineProperty()為對象的屬性賦值時,數據描述符中的屬性默認值是不同的,如下所示。
var o = {};o.a = 1; // 等同于 : Object.defineProperty(o, "a", {value : 1,writable : true,configurable : true,enumerable : true });// 另一方面, Object.defineProperty(o, "a", { value : 1 }); // 等同于 : Object.defineProperty(o, "a", {value : 1,writable : false,configurable : false,enumerable : false });Setters 和Getters
下面的例子說明了如何實現自我存檔的對象。當temperature屬性設置為1時,archive數組會得到一個log。
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);ps: 本文轉自jiangxiaobo博客
轉載于:https://www.cnblogs.com/astonesh/p/8386476.html
總結
以上是生活随笔為你收集整理的JavaScript Object.defineProperty()方法详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 3 利用 Dlib 和 s
- 下一篇: HTML5 CSS3 Transform