{
    "slug": "js_object_property_descriptors",
    "term": "Object Property Descriptors",
    "category": "javascript",
    "difficulty": "advanced",
    "short": "Property descriptors define the hidden attributes of object properties - writable, enumerable, configurable, plus getters and setters.",
    "long": "Getters and setters defined in object literal syntax produce accessor descriptors that are enumerable and configurable, whereas accessors defined in class bodies sit on the prototype and are non-enumerable (but still configurable).",
    "aliases": [
        "defineProperty",
        "getOwnPropertyDescriptor",
        "property attributes",
        "writable enumerable configurable"
    ],
    "tags": [
        "javascript",
        "object-model",
        "metaprogramming",
        "reflection",
        "immutability"
    ],
    "misconception": "People assume Object.defineProperty defaults match normal assignment. In fact defineProperty defaults writable, enumerable, and configurable all to false, so an omitted flag creates a read-only, hidden, locked property.",
    "why_it_matters": "Descriptor flags control serialization, reassignment, and reconfiguration; getting them wrong creates silent update failures or accidentally exposes internal fields through JSON.stringify.",
    "common_mistakes": [
        "Forgetting that Object.defineProperty defaults all flags to false, creating an unexpectedly locked property.",
        "Using spread or Object.assign to clone and losing getters, setters, and non-enumerable flags.",
        "Assuming writable: false throws on reassignment in sloppy mode when it fails silently.",
        "Setting configurable: false too early, then being unable to delete or redefine the property.",
        "Expecting non-enumerable properties to be hidden from Object.getOwnPropertyNames or direct access."
    ],
    "when_to_use": [
        "Defining non-enumerable internal fields you want hidden from serialization and iteration.",
        "Creating computed accessor properties with get/set on existing objects.",
        "Cloning objects while preserving getters, setters, and exact descriptor flags."
    ],
    "avoid_when": [
        "Simple objects where normal assignment with default writable/enumerable/configurable is sufficient.",
        "When the property model is well-served by class fields or plain object literals.",
        "Hot paths where defineProperty per property adds avoidable overhead over direct assignment."
    ],
    "related": [
        "js_object_freeze",
        "js_proxy_reflect",
        "js_prototype",
        "immutability"
    ],
    "prerequisites": [
        "js_prototype"
    ],
    "refs": [
        "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty",
        "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor",
        "https://tc39.es/ecma262/#sec-property-descriptor-specification-type"
    ],
    "bad_code": "config.timeout = 10000; // Silently ignored in sloppy mode; throws TypeError in strict mode/modules\nconsole.log(config.timeout); // 5000",
    "good_code": "const config = {};\n\n// Be explicit about every flag you care about:\nObject.defineProperty(config, 'timeout', {\n    value: 5000,\n    writable: true,\n    enumerable: true,\n    configurable: true,\n});\n\nconfig.timeout = 10000;\nconsole.log(config.timeout); // 10000\nconsole.log(JSON.stringify(config)); // {\"timeout\":10000}\n\n// Clone faithfully, preserving getters and flags:\nconst src = { get id() { return 42; } };\nconst copy = Object.create(\n    Object.getPrototypeOf(src),\n    Object.getOwnPropertyDescriptors(src)\n);\nconsole.log(Object.getOwnPropertyDescriptor(copy, 'id').get); // function",
    "quick_fix": "When using Object.defineProperty, always set writable, enumerable, and configurable explicitly instead of relying on the false defaults.",
    "severity": "medium",
    "effort": "medium",
    "created": "2026-06-01",
    "updated": "2026-06-01",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/js_object_property_descriptors",
        "html_url": "https://codeclaritylab.com/glossary/js_object_property_descriptors",
        "json_url": "https://codeclaritylab.com/glossary/js_object_property_descriptors.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Object Property Descriptors](https://codeclaritylab.com/glossary/js_object_property_descriptors) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/js_object_property_descriptors"
            }
        }
    }
}