--- title: Object.defineProperty() slug: Web/JavaScript/Reference/Global_Objects/Object/defineProperty translation_of: Web/JavaScript/Reference/Global_Objects/Object/defineProperty --- <div>{{JSRef}}</div> <p>靜態方法 <code><strong>Object.defineProperty()</strong></code> 會直接對一個物件定義、或是修改現有的屬性。執行後會回傳定義完的物件。</p> <div class="notecard note"> <p><strong>備註:</strong>這個方法會直接針對 {{jsxref("Object")}} 呼叫建構子(constructor),而不是 <code>Object</code> 型別的實例。</p> </div> <div>{{EmbedInteractiveExample("pages/js/object-defineproperty.html")}}</div> <h2 id="語法">語法</h2> <pre class="syntaxbox"><code>Object.defineProperty(<var>obj</var>, <var>prop</var>, <var>descriptor</var>)</code></pre> <h3 id="參數">參數</h3> <dl> <dt><code>obj</code></dt> <dd>要定義屬性的物件。</dd> <dt><code>prop</code></dt> <dd>要被定義或修改的屬性名字。</dd> <dt><code>descriptor</code></dt> <dd>要定義或修改物件敘述內容。</dd> </dl> <h3 id="回傳值">回傳值</h3> <p>被定義完或修改完屬性的物件。</p> <h2 id="描述">描述</h2> <p>這個函式可以用來增加或修改物件中的屬性定義。在物件建立屬性後,這些屬性同時有被設定預設的設定,才能讓這些屬性被列舉、改變和刪除。而這個函式可以用來改變這些預設的設定。根據預設,被加到物件且使用<code>Object.defineProperty()</code>的值都是{{glossary("Immutable")}}。</p> <p>物件內的屬性描述器(Property descriptor)主要有兩種:資料描述器(data descriptor)與訪問描述器(accessor descriptor)。<dfn>資料描述器</dfn>(data descriptor)是可以選擇能否覆寫的屬性。<dfn>訪問描述器</dfn>(accessor descriptor) is a property described by a getter-setter pair of functions. A descriptor must be one of these two flavors; it cannot be both.</p> <p>data 和 accessor descriptors 皆為物件,兩者共享下面提及的 key:</p> <dl> <dt><code>configurable</code></dt> <dd><code>true</code> 則若且唯若此屬性則將可改變或刪除自相應物件。<br> <strong>預設為 <code>false</code></strong></dd> <dt><code>enumerable</code></dt> <dd><code>true</code> 如果且唯若相應物件被列舉,將會列舉此屬性。<br> <strong>預設為 <code>false</code></strong></dd> </dl> <p>一個 data descriptor 還有以下可選的 key:</p> <dl> <dt><code>value</code></dt> <dd>The value associated with the property. Can be any valid JavaScript value (number, object, function, etc).<br> <strong>預設 {{jsxref("undefined")}}.</strong></dd> <dt><code>writable</code></dt> <dd><code>true</code> 則該物件屬性可透過{{jsxref("Operators/Assignment_Operators", "賦予運算子", "", 1)}}改變其值。<br> <strong>預設 <code>false</code></strong></dd> </dl> <p>一個 accessor descriptor 也擁有下述之 optional keys:</p> <dl> <dt><code>get</code></dt> <dd>作為 getter 形式,為屬性存在的函式,如果沒有 getter 的話則回傳 {{jsxref("undefined")}}。函式回傳將用於屬性值。<br> <strong>預設 {{jsxref("undefined")}}</strong></dd> <dt><code>set</code></dt> <dd>作為 setter 形式,為屬性存在的函式,如果沒有 setter 的話則回傳 {{jsxref("undefined")}}。 The function will receive as only argument the new value being assigned to the property.<br> <strong>預設 {{jsxref("undefined")}}</strong></dd> </dl> <p>請注意,這些選項並不一定要是 descriptor 屬性,由原型鍊(prototype chain)繼承的屬性,也會被考慮到。要確保需要凍結(freeze)的 {{jsxref("Object.prototype")}} upfront 預設能被保存,請明確指定所有選項,或把 {{jsxref("Object.prototype.__proto__", "__proto__")}} 屬性指向 {{jsxref("null")}}。</p> <pre class="brush: js">// using __proto__ var obj = {}; Object.defineProperty(obj, 'key', { __proto__: null, // no inherited properties value: 'static' // not enumerable // not configurable // not writable // as defaults }); // being explicit Object.defineProperty(obj, 'key', { enumerable: false, configurable: false, writable: false, value: 'static' }); // recycling same object function withValue(value) { var d = withValue.d || ( withValue.d = { enumerable: false, writable: false, configurable: false, value: null } ); d.value = value; return d; } // ... and ... Object.defineProperty(obj, 'key', withValue('static')); // if freeze is available, prevents adding or // removing the object prototype properties // (value, get, set, enumerable, writable, configurable) (Object.freeze || Object)(Object.prototype); </pre> <h2 id="範例">範例</h2> <p>If you want to see how to use the <code>Object.defineProperty</code> method with a <em>binary-flags-like</em> syntax, see <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty/Additional_examples">additional examples</a>.</p> <h3 id="建立屬性">建立屬性</h3> <p>When the property specified doesn't exist in the object, <code>Object.defineProperty()</code> creates a new property as described. Fields may be omitted from the descriptor, and default values for those fields are imputed. All of the Boolean-valued fields default to <code>false</code>. The <code>value</code>, <code>get</code>, and <code>set</code> fields default to {{jsxref("undefined")}}. A property which is defined without <code>get</code>/<code>set</code>/<code>value</code>/<code>writable</code> is called “generic” and is “typed” as a data descriptor.</p> <pre class="brush: js">var o = {}; // Creates a new object // 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 }); // 'a' property exists in the o object and its value is 37 // Example of an object property added with defineProperty with an accessor property descriptor var bValue = 38; Object.defineProperty(o, 'b', { get: function() { return bValue; }, set: function(newValue) { bValue = newValue; }, enumerable: true, configurable: true }); o.b; // 38 // 'b' property exists in the o object and its value is 38 // The value of o.b is now always identical to bValue, unless o.b is redefined // You cannot try to mix both: 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 </pre> <h3 id="修改屬性">修改屬性</h3> <p>如果該屬性已經存在, <code>Object.defineProperty()</code> 將會根據描述符內的值和物件當前的 configuration 來修改屬性。 如果舊的描述符之 <code>configurable</code> 的特徵為 false (屬性為 “non-configurable”), 那除了 <code>writable</code> 之外的特徵都將無法修改。 在這個情況,也不可能在 data 和 accessor 屬性類型中來回切換。</p> <p>如果有一個屬性是 non-configurable, 那它的 <code>writable</code> 特徵只能被改變為 <code>false</code>.</p> <p>若嘗試改變 non-configurable property attributes,將會丟出一個 {{jsxref("TypeError")}},除非當前之值與新值相同。</p> <h4 id="Writable_attribute">Writable attribute</h4> <p>當 <code>writable</code> 屬性特徵被設為 <code>false</code>, 此屬性為 “non-writable”. 它將無法被重新賦值。</p> <pre class="brush: js">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. </pre> <p>As seen in the example, trying to write into the non-writable property doesn't change it but doesn't throw an error either.</p> <h4 id="可列舉_attribute">可列舉 attribute</h4> <p>The <code>enumerable</code> property attribute defines whether the property shows up in a {{jsxref("Statements/for...in", "for...in")}} loop and {{jsxref("Object.keys()")}} or not.</p> <pre class="brush: js">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 defaults to true when creating a property by setting it for (var i in o) { console.log(i); } // logs 'a' and 'd' (in undefined order) Object.keys(o); // ['a', 'd'] o.propertyIsEnumerable('a'); // true o.propertyIsEnumerable('b'); // false o.propertyIsEnumerable('c'); // false </pre> <h4 id="可設定_attribute">可設定 attribute</h4> <p>The <code>configurable</code> attribute controls at the same time whether the property can be deleted from the object and whether its attributes (other than <code>writable</code>) can be changed.</p> <pre class="brush: js">var o = {}; Object.defineProperty(o, 'a', { get: function() { return 1; }, configurable: false }); Object.defineProperty(o, 'a', { configurable: true }); // throws a TypeError Object.defineProperty(o, 'a', { enumerable: true }); // throws a TypeError Object.defineProperty(o, 'a', { set: function() {} }); // throws a TypeError (set was undefined previously) Object.defineProperty(o, 'a', { get: function() { return 1; } }); // throws a TypeError (even though the new get does exactly the same thing) Object.defineProperty(o, 'a', { value: 12 }); // throws a TypeError console.log(o.a); // logs 1 delete o.a; // Nothing happens console.log(o.a); // logs 1 </pre> <p>If the <code>configurable</code> attribute of <code>o.a</code> had been <code>true</code>, none of the errors would be thrown and the property would be deleted at the end.</p> <h3 id="新增多個屬性及賦予初始值">新增多個屬性及賦予初始值</h3> <p>It's important to consider the way default values of attributes are applied. There is often a difference between simply using dot notation to assign a value and using <code>Object.defineProperty()</code>, as shown in the example below.</p> <pre class="brush: js">var o = {}; o.a = 1; // is equivalent to: Object.defineProperty(o, 'a', { value: 1, writable: true, configurable: true, enumerable: true }); // On the other hand, Object.defineProperty(o, 'a', { value: 1 }); // is equivalent to: Object.defineProperty(o, 'a', { value: 1, writable: false, configurable: false, enumerable: false }); </pre> <h3 id="Custom_Setters_and_Getters">Custom Setters and Getters</h3> <p>Example below shows how to implement a self-archiving object. When <code>temperature</code> property is set, the <code>archive</code> array gets a log entry.</p> <pre class="brush: js">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 }] </pre> <p>or</p> <pre class="brush: js">var pattern = { get: function () { return 'I always 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'; console.log(instance.myproperty); // I always return this string, whatever you have assigned console.log(instance.myname); // this is my name string </pre> <h2 id="規格">規格</h2> <table class="standard-table"> <tbody> <tr> <th scope="col">Specification</th> <th scope="col">Status</th> <th scope="col">註記</th> </tr> <tr> <td>{{SpecName('ES5.1', '#sec-15.2.3.6', 'Object.defineProperty')}}</td> <td>{{Spec2('ES5.1')}}</td> <td>Initial definition. Implemented in JavaScript 1.8.5.</td> </tr> <tr> <td>{{SpecName('ES6', '#sec-object.defineproperty', 'Object.defineProperty')}}</td> <td>{{Spec2('ES6')}}</td> <td> </td> </tr> <tr> <td>{{SpecName('ESDraft', '#sec-object.defineproperty', 'Object.defineProperty')}}</td> <td>{{Spec2('ESDraft')}}</td> <td> </td> </tr> </tbody> </table> <h2 id="瀏覽器相容性">瀏覽器相容性</h2> <div> <p>{{Compat("javascript.builtins.Object.defineProperty")}}</p> </div> <h2 id="Compatibility_notes">Compatibility notes</h2> <h3 id="Redefining_the_length_property_of_an_Array_object">Redefining the <code>length</code> property of an <code>Array</code> object</h3> <p>It is possible to redefine the {{jsxref("Array.length", "length")}} property of arrays, subject to the usual redefinition restrictions. (The {{jsxref("Array.length", "length")}} property is initially non-configurable, non-enumerable, and writable. Thus on an unaltered array, it's possible to change the {{jsxref("Array.length", "length")}} property's value or to make it non-writable. It is not allowed to change its enumerability or configurability, or if it is non-writable to change its value or writability.) However, not all browsers permit this redefinition.</p> <p>Firefox 4 through 22 will throw a {{jsxref("TypeError")}} on any attempt whatsoever (whether permitted or not) to redefine the {{jsxref("Array.length", "length")}} property of an array.</p> <p>Versions of Chrome which implement <code>Object.defineProperty()</code> in some circumstances ignore a length value different from the array's current {{jsxref("Array.length", "length")}} property. In some circumstances changing writability seems to silently not work (and not throw an exception). Also, relatedly, some array-mutating methods like {{jsxref("Array.prototype.push")}} don't respect a non-writable length.</p> <p>Versions of Safari which implement <code>Object.defineProperty()</code> ignore a <code>length</code> value different from the array's current {{jsxref("Array.length", "length")}} property, and attempts to change writability execute without error but do not actually change the property's writability.</p> <p>Only Internet Explorer 9 and later, and Firefox 23 and later, appear to fully and correctly implement redefinition of the {{jsxref("Array.length", "length")}} property of arrays. For now, don't rely on redefining the {{jsxref("Array.length", "length")}} property of an array to either work, or to work in a particular manner. And even when you <em>can</em> rely on it, <a href="http://whereswalden.com/2013/08/05/new-in-firefox-23-the-length-property-of-an-array-can-be-made-non-writable-but-you-shouldnt-do-it/">there's really no good reason to do so</a>.</p> <h3 id="Internet_Explorer_8_specific_notes">Internet Explorer 8 specific notes</h3> <p>Internet Explorer 8 implemented a <code>Object.defineProperty()</code> method that could <a class="external" href="https://msdn.microsoft.com/en-us/library/dd229916%28VS.85%29.aspx">only be used on DOM objects</a>. A few things need to be noted:</p> <ul> <li>Trying to use <code>Object.defineProperty()</code> on native objects throws an error.</li> <li>Property attributes must be set to some values. The <code>configurable</code>, <code>enumerable</code> and <code>writable</code> attributes should all be set to <code>true</code> for data descriptor and <code>true</code> for <code>configurable</code>, <code>false</code> for <code>enumerable</code> for accessor descriptor.(?) Any attempt to provide other value(?) will result in an error being thrown.</li> <li>Reconfiguring a property requires first deleting the property. If the property isn't deleted, it stays as it was before the reconfiguration attempt.</li> </ul> <h2 id="參閱">參閱</h2> <ul> <li><a href="/zh-TW/docs/Enumerability_and_ownership_of_properties">Enumerability and ownership of properties</a></li> <li>{{jsxref("Object.defineProperties()")}}</li> <li>{{jsxref("Object.propertyIsEnumerable()")}}</li> <li>{{jsxref("Object.getOwnPropertyDescriptor()")}}</li> <li>{{jsxref("Object.prototype.watch()")}}</li> <li>{{jsxref("Object.prototype.unwatch()")}}</li> <li>{{jsxref("Operators/get", "get")}}</li> <li>{{jsxref("Operators/set", "set")}}</li> <li>{{jsxref("Object.create()")}}</li> <li><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty/Additional_examples">Additional <code>Object.defineProperty</code> examples</a></li> <li>{{jsxref("Reflect.defineProperty()")}}</li> </ul>