---
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>