Property Flags & Descriptors
Key Learning Objectives
Understand the 3 core property flags: writable (mutability), enumerable (iteration visibility), and configurable (deletion & descriptor modification).
Master the critical default behavior: Object.defineProperty() defaults omitted flags to false, while normal assignment defaults them to true.
Distinguish between Data Descriptors (value, writable) and Accessor Descriptors (get, set).
Identify silent failures in non-strict mode versus TypeErrors thrown in strict mode for read-only or non-configurable properties.
Know how Object.keys(), Object.getOwnPropertyNames(), and Reflect.ownKeys() handle property enumeration.
The Interview Problem
What is logged to the console when the following code executes, and how do Object.defineProperty descriptor defaults affect enumeration, mutation, and deletion?
1const obj = {};23Object.defineProperty(obj, 'id', {4 value: 101,5 // writable, enumerable, configurable omitted6});78obj.title = 'Widget';910const keys = Object.keys(obj);1112obj.id = 999;1314const deleteId = delete obj.id;1516const ownNames = Object.getOwnPropertyNames(obj);1718console.log(keys.join(','), obj.id, deleteId, ownNames.join(','));
Predict Console Output
Select the option that matches what standard ECMAScript prints to the console:
title 101 false id,title
id,title 999 true id,title
title 999 false title
title 101 true id,title
V8 Engine Execution Trace
Step 1 of 7 (Line 3)Object.defineProperty defines 'id'. Because flags are omitted, the V8 engine defaults writable: false, enumerable: false, configurable: false.
Deep Technical Breakdown
Anatomy of JavaScript Property Descriptors
Every object property in JavaScript possesses an underlying Property Descriptor managed by the engine. Descriptors fall into two mutually exclusive categories:
- Data Descriptors: Describe properties that hold a direct value.
value: The stored JavaScript value (defaultundefined).writable: Iftrue, the value can be changed via assignment. Iffalse, reassignment fails (silently in non-strict mode, throwsTypeErrorin strict mode).
- Accessor Descriptors: Describe properties with getter/setter functions.
get: A function called when reading the property.set: A function called when writing to the property.
(Note: A descriptor cannot have bothvalue/writableandget/setsimultaneously; doing so throws aTypeError.)
- Shared Descriptor Flags:
enumerable: Iftrue, the property appears infor...inloops andObject.keys(). Iffalse, it is omitted.configurable: Iftrue, the property can be deleted viadelete, and its descriptor attributes can be modified. Iffalse,deletefails and changing descriptor flags throws aTypeError.
The Great Default Discrepancy
| Creation Method | writable | enumerable | configurable |
|---|---|---|---|
Assignment (obj.prop = 'val') | true | true | true |
Object.defineProperty (omitted flags) | false | false | false |
Inspection Methods
const descriptor = Object.getOwnPropertyDescriptor(obj, 'prop');
const allDescriptors = Object.getOwnPropertyDescriptors(obj);Introspection Differences
Object.keys(obj): Own enumerable string keys only.Object.getOwnPropertyNames(obj): All own string keys (both enumerable and non-enumerable).Object.getOwnPropertySymbols(obj): All own symbol keys.Reflect.ownKeys(obj): All own keys (both string and symbol, enumerable and non-enumerable).
Strict Mode vs Non-Strict Mode
In non-strict mode:
- Writing to a non-writable property fails silently.
- Deleting a non-configurable property returns
false.
In strict mode ('use strict'):
- Writing to a non-writable property throws
TypeError: Cannot assign to read only property. - Deleting a non-configurable property throws
TypeError: Cannot delete property.
Common Traps & Mistakes
Assuming Object.defineProperty defaults omitted descriptor flags to true. They always default to false.
Mixing data and accessor flags (e.g. providing both value and get), which throws an immediate TypeError.
Thinking Object.freeze() creates a deep freeze. Object.freeze() only sets configurable: false and writable: false on own properties shallowly.
Forgetting that strict mode turns silent property descriptor write failures into fatal runtime exceptions.
FAANG Follow-Up Probes
Probe #1
How does Object.seal() differ from Object.freeze() in terms of property descriptors?
Probe #2
Can you change a property from configurable: false back to configurable: true?
Probe #3
Why does Object.assign() fail to copy getters and setters properly, and how does Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) solve this?
