# attribute

[JS](/web/js.md) ⟩ [value](/web/js/val.md) ⟩ [object](/web/js/val/obj.md) ⟩ [property](/web/js/val/obj/prop.md) ⟩ attribute

{% hint style="success" %}
each [**property**](/web/js/val/obj/prop.md) has a [**name**](/web/js/val/obj/prop/name.md) and <mark style="color:yellow;">**4**</mark> <mark style="color:purple;">**attributes**</mark>：

* <mark style="color:green;">**data**</mark>**&#x20;property** - <mark style="color:red;">**value**</mark> / <mark style="color:orange;">**writable**</mark> / enumerable / configurable
* <mark style="color:blue;">**accessor**</mark>**&#x20;property** - [**get**](/web/js/val/obj/prop/getter-setter.md) / [**set**](/web/js/val/obj/prop/getter-setter.md) / enumerable / configurable
  * can be a getter, setter (only), or getter/setter.

where：

* <mark style="color:orange;">**writable**</mark> - <mark style="color:red;">**value**</mark> (of a data property) <mark style="color:yellow;">**can be**</mark>**&#x20;**<mark style="color:red;">**reassigned**</mark>.
* <mark style="color:orange;">**enumerable**</mark> - **property** <mark style="color:yellow;">**is**</mark>**&#x20;**<mark style="color:red;">**enumerated**</mark> by [**for-in**](/web/js/grammar/statement/loop/for/in.md) loop.
* <mark style="color:orange;">**configurable**</mark> - **property** <mark style="color:yellow;">**can be**</mark> [<mark style="color:red;">**deleted**</mark>](/web/js/val/obj/prop/create/delete.md) / <mark style="color:purple;">**attributes**</mark> <mark style="color:yellow;">**can be**</mark>**&#x20;**<mark style="color:red;">**changed**</mark> (:point\_right: [#zhong-dian](#zhong-dian "mention"))

:u6307: <mark style="color:yellow;">**synonyms**</mark>： "<mark style="color:purple;">**property flag**</mark>"
{% endhint %}

{% tabs %}
{% tab title="🧨 雷區" %}
{% hint style="danger" %}
[**Object.assign()**](/web/js/val/obj/extend/object.assign.md)&#x20;

* <mark style="color:red;">**only**</mark>**&#x20;**<mark style="color:yellow;">**copies**</mark> the <mark style="color:yellow;">**values**</mark> of <mark style="color:green;">**enumerable**</mark> **properties**, <mark style="color:red;">**not**</mark> their <mark style="color:purple;">**attributes**</mark>:exclamation:
* if one of the **source objects** has an <mark style="color:red;">**accessor**</mark>**&#x20;**<mark style="color:yellow;">**property**</mark>, it is the <mark style="color:red;">**value**</mark>**&#x20;**<mark style="color:yellow;">**returned by the**</mark>**&#x20;**<mark style="color:red;">**getter**</mark> that is <mark style="color:yellow;">**copied**</mark> to the **target object**, <mark style="color:red;">**not**</mark>**&#x20;**<mark style="color:yellow;">**the**</mark>**&#x20;**<mark style="color:red;">**getter**</mark>**&#x20;**<mark style="color:yellow;">**itself**</mark>:exclamation:
  {% endhint %}
  {% endtab %}

{% tab title="⭐️ 重點" %}
{% hint style="info" %}
:beginner: <mark style="color:yellow;">**redefine property**</mark>

* <mark style="color:green;">**configurable**</mark> properties
  * :white\_check\_mark: <mark style="color:yellow;">**data**</mark> property -> <mark style="color:blue;">**accessor**</mark> property
  * :white\_check\_mark: <mark style="color:blue;">**accessor**</mark> property -> (<mark style="color:red;">**non-writable**</mark>) <mark style="color:yellow;">**data**</mark> property
  * :white\_check\_mark: <mark style="color:green;">**configurable**</mark> -> <mark style="color:red;">**non-configurable**</mark> ( <mark style="color:yellow;">**one-way**</mark>:exclamation:)
  * :white\_check\_mark: enumerable <-> non-enumerable
  * :white\_check\_mark: writable <-> non-writable
  * :white\_check\_mark: value <-> another value
* <mark style="color:red;">**non-configurable**</mark> properties
  * :white\_check\_mark: <mark style="color:green;">**writable**</mark> -> <mark style="color:red;">**non-writable**</mark> ( <mark style="color:yellow;">**one-way**</mark>:exclamation:)
  * :x: [<mark style="color:red;">**TypeError**</mark>](/web/js/err/type.md) (otherwise)
    {% endhint %}

{% hint style="info" %}
:beginner: <mark style="color:yellow;">**reassign value**</mark> (to <mark style="color:yellow;">**data**</mark> property)

* :white\_check\_mark: <mark style="color:green;">**writable**</mark> - can reassign explicitly. (<mark style="color:blue;">`obj.prop = 1`</mark>)
* :white\_check\_mark: <mark style="color:red;">**non-writable**</mark> , but <mark style="color:green;">**configurable**</mark> - can reassign implicitly.\
  (<mark style="color:blue;">`Object.defineProperty(obj, 'prop', {value: 1})`</mark>)
* :x: [<mark style="color:red;">**TypeError**</mark>](/web/js/err/type.md) (otherwise)
  {% endhint %}

{% hint style="danger" %}

* <mark style="color:red;">**non-writable**</mark> only means that the value can't be reassigned directly.&#x20;
* if <mark style="color:green;">**configurable**</mark>, all the <mark style="color:purple;">**attributes**</mark> could be <mark style="color:yellow;">**changed**</mark> or <mark style="color:yellow;">**overwritten completely**</mark> (data <-> accessor).
  {% endhint %}

{% hint style="info" %}
By default, <mark style="color:yellow;">**all properties**</mark> of the objects you create are <mark style="color:green;">**writable**</mark>, <mark style="color:green;">**enumerable**</mark>, and <mark style="color:green;">**configurable**</mark>.
{% endhint %}
{% endtab %}

{% tab title="🔴 主題" %}

* [property descriptor](/web/js/val/obj/prop/attr/property-descriptor.md) - the attributes of an object.
* [property enumeration](/web/js/val/obj/prop/enumerate.md) - how methods enumerate properties.
* tools
  * [ownPropertyFlags(obj)](/web/js/val/obj/prop/attr/ownpropertyflags-obj.md)
    {% endtab %}

{% tab title="👥 相關" %}

* [obj.mergeWith()](/web/js/val/builtin/object/ext/merge-with.md) - copy properties (and their <mark style="color:purple;">**attributes**</mark>) from other sources.
* [prototype](/web/js/val/func/prototype.md) of a [class](/web/js/val/class.md) is <mark style="color:orange;">**non-writable**</mark>, <mark style="color:orange;">**non-configurable**</mark>, that is, <mark style="color:red;">**can't reassign**</mark> it, <mark style="color:red;">**can't delete**</mark> it or <mark style="color:red;">**change its flags**</mark>.
* used in [isClass()](/web/js/val/type/type-functions/isclass.md) to distinguish between a [function](/web/js/val/func.md) and a [class](/web/js/val/class.md).
* [Object.assign()](/web/js/val/obj/extend/object.assign.md) copies source's **own** **enumerable** properties to target.
  {% endtab %}

{% tab title="💈範例" %}

* replit ⟩ [property attributes](https://replit.com/@pegasusroe/property-attributes-1#index.js) , require ⟩ [Object extension](/web/js/val/builtin/object/ext.md)

```javascript
// ⭐ import
const _Object = require('./ext/Object_ext.js');    // extend Object.prototype
// ---------------------------------------------------------------------------

// ⭐ property attributes
// ----------------------------------------------
// • configurable: can change attributes
// • writable    : can reassign value
// • enumerable  : listed in loops (for-of, ...)

// ⭐ configurable properties
const obj = {                           
                                        
    data: 1,                             // data (writable)
    
    get getter()  { return this.data },  // accessor (getter)
    set setter(v)  {  },                 // accessor (setter only)
    
    get gSetter()  { return this.data }, // accessor (getter/setter)
    set gSetter(v) {  },
};

// ⭐ non-configurable properties
obj.defineProperties({                  
                                        
    x: { value: 1, writable: true },    // data (⭐ writable) (value can be reassigned)
    y: { value: 2 },                    // data (⭐ non-writable)
    
    z : {                               // accessor (getter)
        get() { return "hello" } 
    },           
});

// ⭐ log

// -------------------------------
//     configurable properties
// -------------------------------

// ✅ redefine property

// 1. data -> getter/setter

obj.data,          // 1
obj.defineProperty('data', { get() { return 2 } }), 
obj.propertyDescriptor('data'),
// { get: [Function], set: undefined, enumerable: true, configurable: true }

// 2. getter/setter -> (non-writable) data

obj.getter,        // 2
obj.defineProperty('getter, { value: 'hi' }),      
obj.propertyDescriptor('getter'),
// { value: 'hi', writable: false, enumerable: true, configurable: true }

obj.setter = 3,    // 3
obj.defineProperty('setter', { value: 'jo' }),   
obj.propertyDescriptor('setter'),
// { value: 'jo', writable: false, enumerable: true, configurable: true }

obj.gSetter = 4,    // 4
obj.defineProperty('gSetter', { value: 'bravo' }),   
obj.propertyDescriptor('gSetter'),
// { value: 'bravo', writable: false, enumerable: true, configurable: true }

// -----------------------------------
//     non-configurable properties
// -----------------------------------

// 1. reassign value

// writable
obj.x = 5,    // ✅ OK

// non-writable
obj.y = 6,    // ⛔ TypeError (fails "silently" in sloppy mode❗)
// Cannot assign to read only property 'y' of object

// 2. redefine property

obj.defineProperty('z', { value: 'hi' }),   // ⛔ TypeError
// Cannot redefine property: 'z'
```

{% endtab %}

{% tab title="💾 程式" %}

* replit ⟩ [Object\_ext.js](https://replit.com/@pegasusroe/property-attributes-1#ext/Object_ext.js)

```javascript
// -----------------------------
// ⭐️ extending Object.prototype
// -----------------------------

Object.defineProperties(Object.prototype, {

    // 🔸 obj.defineProperty(prop, desc)
    defineProperty: {
        value: function(prop, descr) {
            return Object.defineProperty(this, prop, descr);
        },
    },

    // 🔸 obj.defineProperties(desc)
    defineProperties: {
        value: function(descr) {
            return Object.defineProperties(this, descr);
        },
    },

    // 🔸 obj.propertyDescriptor(prop)
    propertyDescriptor: {
        value: function(prop) {
            return Object.getOwnPropertyDescriptor(this, prop);
        },
    },

    // 🔸 obj.prototype
    prototype: {
        get: function() {
            return Object.getPrototypeOf(this);
        },
    },

});
```

{% endtab %}

{% tab title="📗 參考" %}

* [ ] JS.info ⟩ [Property flags and descriptors](https://javascript.info/property-descriptors)
* [ ] [JavaScript: The Definitive Guide](/web/master/ref/javascript-the-definitive-guide.md) ⟩&#x20;
  * [ ] 6.3, 6.4, 6.5, 6.6 Querying/Setting/Deleting/Testing/Enumerating Properties
  * [ ] 14.1 Property Attributes
    {% endtab %}

{% tab title="📘 手冊" %}

* [Object.getOwnPropertyDescriptors()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors)
* [Object.defineProperty()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
* [Object.defineProperties()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties)
* [Object.prototype.propertyIsEnumerable()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable)
  {% endtab %}
  {% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lochiwei.gitbook.io/web/js/val/obj/prop/attr.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
