摘要:返回值被傳遞給函數的對象。描述符必須是這兩種形式之一不能同時是兩者。默認為實現內部原理數據描述符同時具有以下可選鍵值與屬性關聯的值。一個沒有定義的屬性被稱為通用的,并被鍵入為一個數據描述符。
Object.defineProperty(obj, prop, descriptor) 該方法允許精確添加或修改對象的屬性。通過賦值來添加的普通屬性會創建在屬性枚舉期間顯示的屬性(for...in 或 Object.keys 方法), 這些值可以被改變,也可以被刪除。這種方法允許這些額外的細節從默認值改變。默認情況下,使用Object.defineProperty()添加的屬性值是不可變的。
`Object.defineProperties(obj, props)`、` Object.defineProperties`本質上定義了`obj` 對象上`props`的`可枚舉屬性`相對應的所有屬性。 `Object.defineProperties(obj, props)`實現
function defineProperties(obj, properties) { function convertToDescriptor(desc) { function hasProperty(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } function isCallable(v) { // NB: modify as necessary if other values than functions are callable. return typeof v === "function"; } if (typeof desc !== "object" || desc === null) throw new TypeError("bad desc"); var d = {}; if (hasProperty(desc, "enumerable")) d.enumerable = !!desc.enumerable; if (hasProperty(desc, "configurable")) d.configurable = !!desc.configurable; if (hasProperty(desc, "value")) d.value = desc.value; if (hasProperty(desc, "writable")) d.writable = !!desc.writable; if (hasProperty(desc, "get")) { var g = desc.get; if (!isCallable(g) && typeof g !== "undefined") throw new TypeError("bad get"); d.get = g; } if (hasProperty(desc, "set")) { var s = desc.set; if (!isCallable(s) && typeof s !== "undefined") throw new TypeError("bad set"); d.set = s; } if (("get" in d || "set" in d) && ("value" in d || "writable" in d)) throw new TypeError("identity-confused descriptor"); return d; } if (typeof obj !== "object" || obj === null) throw new TypeError("bad obj"); properties = Object(properties); var keys = Object.keys(properties); var descs = []; for (var i = 0; i < keys.length; i++) descs.push([keys[i], convertToDescriptor(properties[keys[i]])]); for (var i = 0; i < descs.length; i++) Object.defineProperty(obj, descs[i][0], descs[i][1]); return obj; }
### 參數
`obj `在其上定義或修改屬性的對象。 `prop` 要定義或修改的屬性的名稱。 `descriptor` 將被定義或修改的屬性描述符。 `返回值 ` `被傳遞給函數的對象`。 `props` 要定義其可枚舉屬性或修改的屬性描述符的對象。對象中存在的屬性描述符主要有兩種:`數據描述符`和`訪問器描述符`。描述符具有以下鍵: 數據描述符和存取描述符均具有以下可選鍵值: 對象里目前存在的屬性描述符有兩種主要形式:數據描述符和存取描述符。數據描述符是一個具有值的屬性,該值可能是可寫的,也可能不是可寫的。`存取描述符`是由`getter-setter`函數對描述的屬性。描述符必須是這兩種形式之一;不能同時是兩者。 `configurable` true 當且僅當該屬性描述符的類型可以被改變并且該屬性可以從對應對象中刪除。`默認為 false` `enumerable` true 當且僅當在枚舉相應對象上的屬性時該屬性顯現。` 默認為 false` for ... in obj obj.keys() 實現內部原理 數據描述符同時具有以下可選鍵值: `value` 與屬性關聯的值??梢允侨魏斡行У腏avaScript值(數字,對象,函數等)。 ` 默認為 undefined`. `writable` true當且僅當與該屬性相關聯的值可以用assignment operator改變時。 `默認為 false` 當需要些一些不可以被更改的屬性時可以使用 存取描述符同時具有以下可選鍵值: `get `作為該屬性的 getter 函數,如果沒有 getter 則為undefined。函數返回值將被用作屬性的值。默認為 undefined `set `作為屬性的 setter 函數,如果沒有 setter 則為undefined。函數將僅接受參數賦值給該屬性的新值。默認為 undefined 如果一個描述符不具有value,writable,get 和 set 任意一個關鍵字,那么它將被認為是一個數據描述符。如果一個描述符同時有(value或writable)和(get或set)關鍵字,將會產生一個異常。 記住,這些選項不一定是自身屬性,如果是繼承來的也要考慮。為了確認保留這些默認值,你可能要在這之前凍結 Object.prototype,明確指定所有的選項,或者將__proto__屬性指向null。
使用 __proto__ var obj = {}; var descriptor = Object.create(null); // 沒有繼承的屬性 // 默認沒有 enumerable,沒有 configurable,沒有 writable descriptor.value = "static"; Object.defineProperty(obj, "key", descriptor); // 顯式 Object.defineProperty(obj, "key", { enumerable: false, configurable: false, writable: false, value: "static" }); // 循環使用同一對象 function withValue(value) { var d = withValue.d || ( withValue.d = { enumerable: false, writable: false, configurable: false, value: null } ); d.value = value; return d; } // ... 并且 ... Object.defineProperty(obj, "key", withValue("static")); // 如果 freeze 可用, 防止代碼添加或刪除對象原型的屬性 // (value, get, set, enumerable, writable, configurable) (Object.freeze||Object)(Object.prototype);
###作用: ☆創建屬性 當描述符中省略某些字段時,這些字段將使用它們的默認值。擁有布爾值的字段的默認值都是false。value,get和set字段的默認值為undefined。一個沒有get/set/value/writable定義的屬性被稱為“通用的”,并被“鍵入”為一個數據描述符。 ``` var o = {}; // 創建一個新對象 在對象中添加一個屬性與數據描述符的示例 Object.defineProperty(o, "a", { value : 37, writable : true, enumerable : true, configurable : true }); // 對象o擁有了屬性a,值為37 // 在對象中添加一個屬性與存取描述符的示例 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 // 改變bValue也無法改變o.b console.log(bValue); // o.b的值現在總是與bValue相同,除非重新定義o.b // 數據描述符和存取描述符不能混合使用 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` 為 `false`)。當屬性不可配置時,不能在數據和訪問器屬性類型之間切換。 當試圖改變不可配置屬性(除了writable 屬性之外)的值時會拋出{jsxref("TypeError")}},除非當前值和新值相同。 1 `Writable` 屬性 當writable屬性設置為false時,該屬性被稱為“不可寫”。它不能被重新分配。 試圖寫入非可寫屬性不會改變它,也不會引發錯誤。 ``` var o = {}; // Creates a new object Object.defineProperty(o, "a", { value: 37, writable: false }); console.log(o.a); // logs 37 o.a = 25; // No error thrown // (it would throw in strict mode, // even if the value had been the same) console.log(o.a); // logs 37. The assignment didn"t work. // strict mode (function() { "use strict"; var o = {}; Object.defineProperty(o, "b", { value: 2, writable: false }); o.b = 3; // throws TypeError: "b" is read-only return o.b; // returns 2 without the line above }());
2 `Enumerable `特性 enumerable定義了對象的屬性是否可以在 for...in 循環和 Object.keys() 中被枚舉默認是true。
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為true for (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"); // false ``` 3 Configurable 特性 configurable特性表示對象的屬性是否可以被刪除,以及除writable特性外的其他特性是否可以被修改。 如果o.a的configurable屬性為true,則不會拋出任何錯誤,并且該屬性將在最后被刪除。 var o = {}; Object.defineProperty(o, "a", { get : function(){return 1;}, configurable : false } ); //為true時,不會報錯 結果為12 undefined(可以刪除) // throws a TypeError Cannot redefine property: a 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 }); ``` ☆ 一般的 `Setter` 和 `Getters` 下面的例子展示了如何實現一個自存檔對象。 當設置temperature 屬性時,archive 數組會獲取日志條目。 ``` 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); ``` ☆ ☆兼容性問題 1 數組的 length 屬性重定義是可能的,但是會受到一般的重定義限制。(length 屬性初始為 non-configurable,non-enumerable 以及 writable。對于一個內容不變的數組,改變其 length 屬性的值或者使它變為 non-writable 是可能的。但是改變其可枚舉性和可配置性或者當它是 non-writable 時嘗試改變它的值或是可寫性,這兩者都是不允許的。)然而,并不是所有的瀏覽器都允許 Array.length 的重定義。 在 Firefox 4 至 22 版本中嘗試去重定義數組的 length 屬性都會拋出一個 TypeError 異常。 有些版本的Chrome中,Object.defineProperty() 在某些情況下會忽略不同于數組當前length屬性的length值。有些情況下改變可寫性并不起作用(也不拋出異常)。同時,比如Array.prototype.push的一些數組操作方法也不會考慮不可讀的length屬性。 有些版本的Safari中,Object.defineProperty() 在某些情況下會忽略不同于數組當前length屬性的length值。嘗試改變可寫性的操作會正常執行而不拋出錯誤,但事實上并未改變屬性的可寫性。 只在Internet Explorer 9及以后版本和Firefox 23及以后版本中,才完整地正確地支持數組length屬性的重新定義。目前不要依賴于重定義數組length 屬性能夠起作用,或在特定情形下起作用。與此同時,即使你能夠依賴于它,你也沒有合適的理由這樣做。 2 Internet Explorer 8 具體案例 Internet Explorer 8 實現了 Object.defineProperty() 方法,但 只能在 DOM 對象上使用。 需要注意的一些事情: 嘗試在原生對象上使用 Object.defineProperty()會報錯。 屬性特性必須設置一些特定的值。對于數據屬性描述符,configurable, enumerable 和 writable 特性必須全部設置為 true;對于訪問器屬性描述符,configurable 必須設置為 true,enumerable 必須設置為 false。(?) 任何試圖提供其他值(?)將導致一個錯誤拋出。 重新配置一個屬性首先需要刪除該屬性。如果屬性沒有刪除,就如同重新配置前的嘗試。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/96101.html
摘要:與當與同時為時,屬性不能重新使用定義,嚴格模式下會報錯示例云麒報錯當或者為時,屬性可以重新使用定義,這一點讀者不妨自行測試。 摘要: JavaScript有個很神奇的Object.defineProperty(),了解一下? =與Object.defineProperty 為JavaScript對象新增或者修改屬性,有兩種不同方式:直接使用=賦值或者使用Object.definePro...
摘要:概念中定義了一個名叫屬性描述符的對象,用于描述了的各種特征。只指定則表示屬性為只讀屬性。使用屬性描述符對象只能在或中使用。修改已有的屬性會拋出類型錯誤異常添加屬性會拋出類型錯誤異常不能修屬性結語我對屬性描述符很不熟悉,主要是因為平時用得少。 概念 ECMAScript 5 中定義了一個名叫屬性描述符的對象,用于描述了的各種特征。屬性描述符對象有4個屬性: configurable:可...
摘要:返回值被傳遞給函數的對象。描述該方法允許精確添加或修改對象的屬性。描述符必須是兩種形式之一不能同時是兩者??梢允侨魏斡行У闹禂抵担瑢ο螅瘮档?。該方法返回值被用作屬性值。該方法將接受唯一參數,并將該參數的新值分配給該屬性。 Object.defineProperties() Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性...
摘要:的使用對象是由多個名值對組成的無序的集合。目標屬性所擁有的特性返回值傳入函數的對象。是一種獲得屬性值的方法是一種設置屬性值的方法。參考相關閱讀鏈接基礎篇中的可枚舉屬性與不可枚舉屬性以及擴展 Math.max 實現得到數組中最大的一項 var array = [1,2,3,4,5]; var max = Math.max.apply(null, array); console.log(m...
摘要:可枚舉性屬性是一個布爾值,表示目標屬性是否可枚舉??膳渲眯苑祷匾粋€布爾值,決定了是否可以修改屬性描述對象。其中,存值函數稱為,使用屬性描述對象的屬性取值函數稱為,使用屬性描述對象的屬性。 JavaScript 提供了一個內部數據結構,用來描述對象的屬性,控制它的行為,比如該屬性是否可寫、可枚舉等等。這個內部數據結構稱為屬性描述對象(attributes object)。每個屬性都有自己...
閱讀 929·2023-04-26 01:34
閱讀 3363·2023-04-25 20:58
閱讀 3289·2021-11-08 13:22
閱讀 2118·2019-08-30 14:17
閱讀 2526·2019-08-29 15:27
閱讀 2679·2019-08-29 12:45
閱讀 3004·2019-08-29 12:26
閱讀 2816·2019-08-28 17:51