摘要:返回值被傳遞給函數(shù)的對(duì)象。描述符必須是這兩種形式之一不能同時(shí)是兩者。默認(rèn)為實(shí)現(xiàn)內(nèi)部原理數(shù)據(jù)描述符同時(shí)具有以下可選鍵值與屬性關(guān)聯(lián)的值。一個(gè)沒(méi)有定義的屬性被稱為通用的,并被鍵入為一個(gè)數(shù)據(jù)描述符。
Object.defineProperty(obj, prop, descriptor) 該方法允許精確添加或修改對(duì)象的屬性。通過(guò)賦值來(lái)添加的普通屬性會(huì)創(chuàng)建在屬性枚舉期間顯示的屬性(for...in 或 Object.keys 方法), 這些值可以被改變,也可以被刪除。這種方法允許這些額外的細(xì)節(jié)從默認(rèn)值改變。默認(rèn)情況下,使用Object.defineProperty()添加的屬性值是不可變的。
`Object.defineProperties(obj, props)`、` Object.defineProperties`本質(zhì)上定義了`obj` 對(duì)象上`props`的`可枚舉屬性`相對(duì)應(yīng)的所有屬性。 `Object.defineProperties(obj, props)`實(shí)現(xiàn)
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; }
### 參數(shù)
`obj `在其上定義或修改屬性的對(duì)象。 `prop` 要定義或修改的屬性的名稱。 `descriptor` 將被定義或修改的屬性描述符。 `返回值 ` `被傳遞給函數(shù)的對(duì)象`。 `props` 要定義其可枚舉屬性或修改的屬性描述符的對(duì)象。對(duì)象中存在的屬性描述符主要有兩種:`數(shù)據(jù)描述符`和`訪問(wèn)器描述符`。描述符具有以下鍵: 數(shù)據(jù)描述符和存取描述符均具有以下可選鍵值: 對(duì)象里目前存在的屬性描述符有兩種主要形式:數(shù)據(jù)描述符和存取描述符。數(shù)據(jù)描述符是一個(gè)具有值的屬性,該值可能是可寫(xiě)的,也可能不是可寫(xiě)的。`存取描述符`是由`getter-setter`函數(shù)對(duì)描述的屬性。描述符必須是這兩種形式之一;不能同時(shí)是兩者。 `configurable` true 當(dāng)且僅當(dāng)該屬性描述符的類型可以被改變并且該屬性可以從對(duì)應(yīng)對(duì)象中刪除。`默認(rèn)為 false` `enumerable` true 當(dāng)且僅當(dāng)在枚舉相應(yīng)對(duì)象上的屬性時(shí)該屬性顯現(xiàn)。` 默認(rèn)為 false` for ... in obj obj.keys() 實(shí)現(xiàn)內(nèi)部原理 數(shù)據(jù)描述符同時(shí)具有以下可選鍵值: `value` 與屬性關(guān)聯(lián)的值??梢允侨魏斡行У腏avaScript值(數(shù)字,對(duì)象,函數(shù)等)。 ` 默認(rèn)為 undefined`. `writable` true當(dāng)且僅當(dāng)與該屬性相關(guān)聯(lián)的值可以用assignment operator改變時(shí)。 `默認(rèn)為 false` 當(dāng)需要些一些不可以被更改的屬性時(shí)可以使用 存取描述符同時(shí)具有以下可選鍵值: `get `作為該屬性的 getter 函數(shù),如果沒(méi)有 getter 則為undefined。函數(shù)返回值將被用作屬性的值。默認(rèn)為 undefined `set `作為屬性的 setter 函數(shù),如果沒(méi)有 setter 則為undefined。函數(shù)將僅接受參數(shù)賦值給該屬性的新值。默認(rèn)為 undefined 如果一個(gè)描述符不具有value,writable,get 和 set 任意一個(gè)關(guān)鍵字,那么它將被認(rèn)為是一個(gè)數(shù)據(jù)描述符。如果一個(gè)描述符同時(shí)有(value或writable)和(get或set)關(guān)鍵字,將會(huì)產(chǎn)生一個(gè)異常。 記住,這些選項(xiàng)不一定是自身屬性,如果是繼承來(lái)的也要考慮。為了確認(rèn)保留這些默認(rèn)值,你可能要在這之前凍結(jié) Object.prototype,明確指定所有的選項(xiàng),或者將__proto__屬性指向null。
使用 __proto__ var obj = {}; var descriptor = Object.create(null); // 沒(méi)有繼承的屬性 // 默認(rèn)沒(méi)有 enumerable,沒(méi)有 configurable,沒(méi)有 writable descriptor.value = "static"; Object.defineProperty(obj, "key", descriptor); // 顯式 Object.defineProperty(obj, "key", { enumerable: false, configurable: false, writable: false, value: "static" }); // 循環(huán)使用同一對(duì)象 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 可用, 防止代碼添加或刪除對(duì)象原型的屬性 // (value, get, set, enumerable, writable, configurable) (Object.freeze||Object)(Object.prototype);
###作用: ☆創(chuàng)建屬性 當(dāng)描述符中省略某些字段時(shí),這些字段將使用它們的默認(rèn)值。擁有布爾值的字段的默認(rèn)值都是false。value,get和set字段的默認(rèn)值為undefined。一個(gè)沒(méi)有g(shù)et/set/value/writable定義的屬性被稱為“通用的”,并被“鍵入”為一個(gè)數(shù)據(jù)描述符。 ``` var o = {}; // 創(chuàng)建一個(gè)新對(duì)象 在對(duì)象中添加一個(gè)屬性與數(shù)據(jù)描述符的示例 Object.defineProperty(o, "a", { value : 37, writable : true, enumerable : true, configurable : true }); // 對(duì)象o擁有了屬性a,值為37 // 在對(duì)象中添加一個(gè)屬性與存取描述符的示例 var bValue; Object.defineProperty(o, "b", { get : function(){ return bValue; }, set : function(newValue){ bValue = newValue; }, enumerable : true, configurable : true }); o.b = 38; // 對(duì)象o擁有了屬性b,值為38 // 改變bValue也無(wú)法改變o.b console.log(bValue); // o.b的值現(xiàn)在總是與bValue相同,除非重新定義o.b // 數(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ù)描述符中的值以及對(duì)象當(dāng)前的配置來(lái)修改這個(gè)屬性。如果舊描述符將其`configurable` 屬性設(shè)置為`false`,則該屬性被認(rèn)為是`“不可配置的”`,并且沒(méi)有屬性可以被改變(除了單向改變 `writable` 為 `false`)。當(dāng)屬性不可配置時(shí),不能在數(shù)據(jù)和訪問(wèn)器屬性類型之間切換。 當(dāng)試圖改變不可配置屬性(除了writable 屬性之外)的值時(shí)會(huì)拋出{jsxref("TypeError")}},除非當(dāng)前值和新值相同。 1 `Writable` 屬性 當(dāng)writable屬性設(shè)置為false時(shí),該屬性被稱為“不可寫(xiě)”。它不能被重新分配。 試圖寫(xiě)入非可寫(xiě)屬性不會(huì)改變它,也不會(huì)引發(fā)錯(cuò)誤。 ``` 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定義了對(duì)象的屬性是否可以在 for...in 循環(huán)和 Object.keys() 中被枚舉默認(rèn)是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; // 如果使用直接賦值的方式創(chuàng)建對(duì)象的屬性,則這個(gè)屬性的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特性表示對(duì)象的屬性是否可以被刪除,以及除writable特性外的其他特性是否可以被修改。 如果o.a的configurable屬性為true,則不會(huì)拋出任何錯(cuò)誤,并且該屬性將在最后被刪除。 var o = {}; Object.defineProperty(o, "a", { get : function(){return 1;}, configurable : false } ); //為true時(shí),不會(huì)報(bào)錯(cuò) 結(jié)果為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 ``` ☆ 添加多個(gè)屬性和默認(rèn)值 考慮特性被賦予的默認(rèn)特性值非常重要,通常,使用點(diǎn)運(yùn)算符和Object.defineProperty()為對(duì)象的屬性賦值時(shí),數(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 }); ``` ☆ 一般的 `Setter` 和 `Getters` 下面的例子展示了如何實(shí)現(xiàn)一個(gè)自存檔對(duì)象。 當(dāng)設(shè)置temperature 屬性時(shí),archive 數(shù)組會(huì)獲取日志條目。 ``` 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); ``` ☆ ☆兼容性問(wèn)題 1 數(shù)組的 length 屬性重定義是可能的,但是會(huì)受到一般的重定義限制。(length 屬性初始為 non-configurable,non-enumerable 以及 writable。對(duì)于一個(gè)內(nèi)容不變的數(shù)組,改變其 length 屬性的值或者使它變?yōu)?non-writable 是可能的。但是改變其可枚舉性和可配置性或者當(dāng)它是 non-writable 時(shí)嘗試改變它的值或是可寫(xiě)性,這兩者都是不允許的。)然而,并不是所有的瀏覽器都允許 Array.length 的重定義。 在 Firefox 4 至 22 版本中嘗試去重定義數(shù)組的 length 屬性都會(huì)拋出一個(gè) TypeError 異常。 有些版本的Chrome中,Object.defineProperty() 在某些情況下會(huì)忽略不同于數(shù)組當(dāng)前l(fā)ength屬性的length值。有些情況下改變可寫(xiě)性并不起作用(也不拋出異常)。同時(shí),比如Array.prototype.push的一些數(shù)組操作方法也不會(huì)考慮不可讀的length屬性。 有些版本的Safari中,Object.defineProperty() 在某些情況下會(huì)忽略不同于數(shù)組當(dāng)前l(fā)ength屬性的length值。嘗試改變可寫(xiě)性的操作會(huì)正常執(zhí)行而不拋出錯(cuò)誤,但事實(shí)上并未改變屬性的可寫(xiě)性。 只在Internet Explorer 9及以后版本和Firefox 23及以后版本中,才完整地正確地支持?jǐn)?shù)組length屬性的重新定義。目前不要依賴于重定義數(shù)組length 屬性能夠起作用,或在特定情形下起作用。與此同時(shí),即使你能夠依賴于它,你也沒(méi)有合適的理由這樣做。 2 Internet Explorer 8 具體案例 Internet Explorer 8 實(shí)現(xiàn)了 Object.defineProperty() 方法,但 只能在 DOM 對(duì)象上使用。 需要注意的一些事情: 嘗試在原生對(duì)象上使用 Object.defineProperty()會(huì)報(bào)錯(cuò)。 屬性特性必須設(shè)置一些特定的值。對(duì)于數(shù)據(jù)屬性描述符,configurable, enumerable 和 writable 特性必須全部設(shè)置為 true;對(duì)于訪問(wèn)器屬性描述符,configurable 必須設(shè)置為 true,enumerable 必須設(shè)置為 false。(?) 任何試圖提供其他值(?)將導(dǎo)致一個(gè)錯(cuò)誤拋出。 重新配置一個(gè)屬性首先需要?jiǎng)h除該屬性。如果屬性沒(méi)有刪除,就如同重新配置前的嘗試。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/96101.html
摘要:與當(dāng)與同時(shí)為時(shí),屬性不能重新使用定義,嚴(yán)格模式下會(huì)報(bào)錯(cuò)示例云麒報(bào)錯(cuò)當(dāng)或者為時(shí),屬性可以重新使用定義,這一點(diǎn)讀者不妨自行測(cè)試。 摘要: JavaScript有個(gè)很神奇的Object.defineProperty(),了解一下? =與Object.defineProperty 為JavaScript對(duì)象新增或者修改屬性,有兩種不同方式:直接使用=賦值或者使用Object.definePro...
摘要:概念中定義了一個(gè)名叫屬性描述符的對(duì)象,用于描述了的各種特征。只指定則表示屬性為只讀屬性。使用屬性描述符對(duì)象只能在或中使用。修改已有的屬性會(huì)拋出類型錯(cuò)誤異常添加屬性會(huì)拋出類型錯(cuò)誤異常不能修屬性結(jié)語(yǔ)我對(duì)屬性描述符很不熟悉,主要是因?yàn)槠綍r(shí)用得少。 概念 ECMAScript 5 中定義了一個(gè)名叫屬性描述符的對(duì)象,用于描述了的各種特征。屬性描述符對(duì)象有4個(gè)屬性: configurable:可...
摘要:返回值被傳遞給函數(shù)的對(duì)象。描述該方法允許精確添加或修改對(duì)象的屬性。描述符必須是兩種形式之一不能同時(shí)是兩者??梢允侨魏斡行У闹禂?shù)值,對(duì)象,函數(shù)等。該方法返回值被用作屬性值。該方法將接受唯一參數(shù),并將該參數(shù)的新值分配給該屬性。 Object.defineProperties() Object.defineProperty() 方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性...
摘要:的使用對(duì)象是由多個(gè)名值對(duì)組成的無(wú)序的集合。目標(biāo)屬性所擁有的特性返回值傳入函數(shù)的對(duì)象。是一種獲得屬性值的方法是一種設(shè)置屬性值的方法。參考相關(guān)閱讀鏈接基礎(chǔ)篇中的可枚舉屬性與不可枚舉屬性以及擴(kuò)展 Math.max 實(shí)現(xiàn)得到數(shù)組中最大的一項(xiàng) var array = [1,2,3,4,5]; var max = Math.max.apply(null, array); console.log(m...
摘要:可枚舉性屬性是一個(gè)布爾值,表示目標(biāo)屬性是否可枚舉。可配置性返回一個(gè)布爾值,決定了是否可以修改屬性描述對(duì)象。其中,存值函數(shù)稱為,使用屬性描述對(duì)象的屬性取值函數(shù)稱為,使用屬性描述對(duì)象的屬性。 JavaScript 提供了一個(gè)內(nèi)部數(shù)據(jù)結(jié)構(gòu),用來(lái)描述對(duì)象的屬性,控制它的行為,比如該屬性是否可寫(xiě)、可枚舉等等。這個(gè)內(nèi)部數(shù)據(jù)結(jié)構(gòu)稱為屬性描述對(duì)象(attributes object)。每個(gè)屬性都有自己...
閱讀 937·2023-04-26 01:34
閱讀 3371·2023-04-25 20:58
閱讀 3324·2021-11-08 13:22
閱讀 2126·2019-08-30 14:17
閱讀 2537·2019-08-29 15:27
閱讀 2687·2019-08-29 12:45
閱讀 3011·2019-08-29 12:26
閱讀 2824·2019-08-28 17:51