> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/web/js/val/obj/prop/attr.md).

# attribute

(value/writable) | (get/set) / enumerable / configurable

[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 %}
