javascript
JavaScript Object.defineProperty()方法详解
Object.defineProperty() 方法直接在一個對象上定義一個新屬性,或者修改一個已經(jīng)存在的屬性,并返回這個對象。因此,又稱為屬性攔截器。在前端中,webpack以及vue的原理都應(yīng)用了這個方法。
語法
Object.defineProperty(obj, prop, descriptor)參數(shù)
- obj ?需要定義屬性的對象。
- prop ?需要定義或者修改的屬性名。
- descriptor ?需要定義或者修改的屬性的描述符。
描述
該方法允許精確添加或者修改對象的屬性。一般情況下,我們?yōu)閷ο筇砑訉傩允峭ㄟ^賦值來創(chuàng)建并顯示在屬性枚舉中(for...in或者Object.keys方法),但這種添加的屬性值可以被改變,也可以被刪除。而使用Object.defineProperty()則允許改變這些額外細(xì)節(jié)的默認(rèn)設(shè)置。比如,默認(rèn)情況下使用Object.defineProperty()增加的屬性是不可改變的。
對象里目前存在的屬性描述符有兩種主要形式:
數(shù)據(jù)描述符和存取描述符
數(shù)據(jù)描述符是一個擁有可寫或者不可寫的屬性。存取描述符是由一對setter-getter函數(shù)功能來描述的屬性。描述符必須是兩種形式之一,不能同時是兩種。
數(shù)據(jù)描述符合存取符均具有以下可選鍵值:
- configurable ?僅當(dāng)該屬性為true時,該屬性才能夠被改變,也能被刪除。默認(rèn)為false。
- enumerable ? 僅當(dāng)該屬性為true時,該屬性才能出現(xiàn)在對象的枚舉屬性中。默認(rèn)為false。
- value ?該屬性對應(yīng)的值。可以是任何有效的Javascript值,包括數(shù)值、對象和函數(shù)等。默認(rèn)值為underfined。
- writable ?僅當(dāng)該屬性為true時,該屬性才能被賦值被改變。默認(rèn)為false。
- get ?一個屬性提供的getter方法。如果沒有g(shù)etter則為undefined。該方法返回值作為對象屬性的賦值。默認(rèn)為undefined。
- set??一個屬性提供的setter方法。如果沒有setter則為undefined。該方法將接受唯一參數(shù),并將該參數(shù)的新值分配給該屬性。默認(rèn)為undefined。
創(chuàng)建屬性
如果對象中不存在指定的屬性,Object.defineProperty()就創(chuàng)建這個屬性。當(dāng)描述符中省略某些字段時,這些字段將使用它們的默認(rèn)值。擁有布爾值的字段的默認(rèn)值都是false。value,get和set字段的默認(rèn)值為undefined。定義屬性時如果沒有g(shù)et/set/value/writable,那它將被歸為數(shù)據(jù)類描述。
var o = {}; // 創(chuàng)建一個新對象// 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// 數(shù)據(jù)描述符和存取描述符不能混合使用 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修改屬性
如果屬性已經(jīng)存在,Object.defineProperty()將嘗試根據(jù)描述符的值以及對象當(dāng)前的配置來修改這個屬性。如果描述的configurable特性為false,那么除了writable外,其他特性都不能被修改,并且數(shù)據(jù)和存取描述符也不能相互切磋。
如果configurable為false,則其writable特性也只能為false。
如果嘗試修改該值時,那么將會出現(xiàn)TypeError。
Writable屬性
當(dāng)屬性特性writable設(shè)置為false時,表示non-writable,屬性將不能被修改。修改一個non-writable的屬性不會改變屬性的值,同時也不會報出異常。
var o = {}; // 創(chuàng)建一個新對象Object.defineProperty(o, "a", { value : 37,writable : false });console.log(o.a); // 打印 37 o.a = 25; // 沒有錯誤拋出(在嚴(yán)格模式下會拋出,即使之前已經(jīng)有相同的值) console.log(o.a); // 打印 37, 賦值不起作用。Enumerable 特性
屬性特性enumerable定義了對象的屬性是否可以在for...in循環(huán)和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; // 如果使用直接賦值的方式創(chuàng)建對象的屬性,則這個屬性的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添加多個屬性和默認(rèn)值
考慮特性被賦予的默認(rèn)特性值非常重要,通常,使用點運算符和Object.defineProperty()為對象的屬性賦值時,數(shù)據(jù)描述符中的屬性默認(rèn)值是不同的,如下所示。
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
下面的例子說明了如何實現(xiàn)自我存檔的對象。當(dāng)temperature屬性設(shè)置為1時,archive數(shù)組會得到一個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: 本文轉(zhuǎn)自jiangxiaobo博客
轉(zhuǎn)載于:https://www.cnblogs.com/astonesh/p/8386476.html
總結(jié)
以上是生活随笔為你收集整理的JavaScript Object.defineProperty()方法详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 3 利用 Dlib 和 s
- 下一篇: JavaScript If…Else 语