diff options
Diffstat (limited to 'files/zh-tw/web/javascript/reference/global_objects/object/defineproperty/index.html')
| -rw-r--r-- | files/zh-tw/web/javascript/reference/global_objects/object/defineproperty/index.html | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/files/zh-tw/web/javascript/reference/global_objects/object/defineproperty/index.html b/files/zh-tw/web/javascript/reference/global_objects/object/defineproperty/index.html new file mode 100644 index 0000000000..cf83590181 --- /dev/null +++ b/files/zh-tw/web/javascript/reference/global_objects/object/defineproperty/index.html @@ -0,0 +1,380 @@ +--- +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="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> 特徵只能被改變為 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">false</span></font>.</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> |
