cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Enumerability & ownership

Learn which JavaScript properties are own, inherited, enumerable, hidden, string, or symbol keys, and which loop or method can see each one.

What you’ll be able to predict
  • 01
    Answer the two visibility questionsDecide whether a property is own or inherited, and public or hidden.
  • 02
    Choose the right key readerCompare Object.keys, for...in, Reflect.ownKeys, names, and symbols.
  • 03
    Predict key orderUse JavaScript’s integer, string, and symbol ordering rules.

Two visibility questions

JavaScript objects can hold more properties than a quick loop shows. Some properties live directly on the object. Some are inherited from an ancestor through the prototype chain. Some are public, and some are intentionally left out of ordinary lists.

This lesson is the map. For every property, ask two questions first:

  1. Ownership: is the property stored on this object, or found on an inherited ancestor?
  2. Enumerability: is it listed in the public directory, or kept in the object’s private records?
Real-life analogyA property has a public directory entry

Imagine a directory that prints only public records. The record can belong to your house or to an ancestor’s office, and it can be printed or hidden. JavaScript key-reading methods are different clerks who are allowed to read different shelves.

In real life: A house's own record
In JavaScript: An own property
In real life: A record at a parent office
In JavaScript: An inherited property
In real life: Printed in the public directory
In JavaScript: enumerable: true
In real life: Kept in a private cabinet
In JavaScript: enumerable: false

Where the analogy stops: A real directory controls privacy. JavaScript enumerability does not make a value secret; it only changes which listing tools skip it.

You already met the enumerable descriptor flag in Property flags & descriptors, for...in, Object.keys, symbols, and the prototype chain. Now we put them together so you can predict exactly who sees what.

Own vs inherited

STEP THROUGH

An own property is stored directly on the object. An inherited property is found by following the object’s prototype chain. Normal property reads do not care where a property was found, but listing tools often do.

Step through this tiny object. Predict which checks return true before you run them.

Own property or inherited lookup?
Step 0 of 6Ready
Your turn: follow the blue line

Predict which checks are true. Then step through ownership versus lookup.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const user = Object.create(prototype);user.name = "Ada"; console.log(Object.hasOwn(user, "name"));console.log(Object.hasOwn(user, "inheritedRole"));console.log("inheritedRole" in user);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Use the right question

Object.hasOwn(obj, key) asks “is it stored here?” The in operator asks “can normal lookup find it anywhere?” They are both useful, but they answer different questions.

Enumerable vs non-enumerable

Enumerability is a property descriptor flag. Assignment and object literal syntax usually create enumerable properties. The Object.defineProperty default is the opposite: unless you set enumerable: true, the property is non-enumerable.

Non-enumerable does not mean private. Code can still read the property if it knows the name, and descriptor tools can still find it. It only means public listing tools such as Object.keys, for...in, and JSON.stringify skip it.

The two axes are independent
QuestionPublic / enumerableHidden / non-enumerable
Own propertyobj.name = "Ada" appears in Object.keysdefineProperty(obj, "secret", { value: 1 }) stays off Object.keys
Inherited propertyfor...in can list itNormal lookup can find it, but listing tools skip it
String keyCommon lists include itgetOwnPropertyNames can still find it
Symbol keySpread and Object.assign copy itgetOwnPropertySymbols and Reflect.ownKeys can find it

Object.keys vs for…in vs Reflect.ownKeys

INTERACTIVE

The most common confusion is treating every key reader like a bigger or smaller version of Object.keys. They are not. Each one has its own rule about ownership, enumerability, and key type.

  • Object.keys, Object.values, and Object.entries read own enumerable string keys.
  • for...in reads enumerable string keys on the object and then on its ancestors.
  • JSON.stringify uses own enumerable string keys and skips symbols.
  • Object.assign and object spread copy own enumerable string and symbol keys.
  • Reflect.ownKeys reads the complete set of own keys: strings and symbols, enumerable or not.
Who sees what?
Matrix setupPop out in the code editor (opens in a new tab)JavaScript
const shown = Symbol("shown");const hiddenSymbol = Symbol("hidden");const proto = { inheritedEnum: "from prototype" };Object.defineProperty(proto, "inheritedHidden", { value: "secret" });const item = Object.create(proto);item[2] = "integer-like";item.title = "Guide";Object.defineProperty(item, "secret", { value: 42 });item[shown] = "symbol value";Object.defineProperty(item, hiddenSymbol, { value: "symbol secret" });
ReaderActual result

Results appear after mount so the server never guesses for the browser.

Try it yourself

Preparing the browser-run results…

The object has an own enumerable string, an own non-enumerable string, symbols, inherited keys, and an integer-like key.
Fun fact

Object.values and Object.entries do not have their own visibility rule. They use the same keys as Object.keys, then return values or pairs for those keys.

getOwnPropertyNames & getOwnPropertySymbols

Strings and symbols use separate doors. Object.getOwnPropertyNames returns all own string keys, including non-enumerable ones. Object.getOwnPropertySymbols returns all own symbol keys, including non-enumerable ones. Put them together when you need both lists, or use Reflect.ownKeys when you want one complete own-key list.

Real-life analogyReflect.ownKeys is the complete file drawer

Some clerks read only public names. Some read hidden names. Some read the symbol drawer. Reflect.ownKeys is the one who opens the complete folder for this object and returns every own key.

In real life: Public directory
In JavaScript: Object.keys
In real life: String-name drawer
In JavaScript: Object.getOwnPropertyNames
In real life: Symbol drawer
In JavaScript: Object.getOwnPropertySymbols
In real life: Every own record in one folder
In JavaScript: Reflect.ownKeys

Where the analogy stops: Reflect has many other methods in JavaScript. This lesson only introduces Reflect.ownKeys; the Reflect lesson covers the larger API later.

Listed by Object.keys?
  • Own enumerable string key
  • Own non-enumerable string key
  • Inherited enumerable string key
  • Own enumerable symbol key
  • Own enumerable key "0" on an array
  • Array length
Try it yourself
0 of 6 correct

Sort each property kind. The rule is strict: own, enumerable, and string.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Property order rules

STEP THROUGH

Modern JavaScript has defined order for ordinary own-key readers. The order is not simply “the order I typed everything.” It has three buckets:

  1. Integer-index string keys first, in numeric order.
  2. Other string keys next, in insertion order.
  3. Symbol keys last, in insertion order.

A practical integer-like key is a canonical non-negative integer string such as "2" or "10". Strings like "01" and "-1" stay in the normal string bucket.

Step through property order
Step 0 of 6Ready
Your turn: follow the blue line

Step through the three property-order buckets: integer-like strings, other strings, symbols.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const b = Symbol("b");const record = { "10": "ten", "2": "two" };record.name = "Ada";record.city = "Pune";record[b] = "second symbol";record[a] = "first symbol"; console.log(Reflect.ownKeys(record));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Choose the key mix

Changing the choice starts a fresh replay. Predict the final Reflect.ownKeys order first.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Built-ins hide their housekeeping

INTERACTIVE

Built-in objects use these same flags. Array indexes are enumerable, so Object.keys(["a", "b"]) returns ["0", "1"]. The array’s length property exists, but it is non-enumerable, so it does not appear in Object.keys or for...in.

Class methods follow the same idea. They live on the class prototype and are non-enumerable, so data loops over an instance are not filled with method names.

Built-ins keep their housekeeping hidden
Array and class checksPop out in the code editor (opens in a new tab)JavaScript
class Counter {  increment() {    return 1;  }} const array = ["a", "b"];const counter = new Counter(); console.log(Object.keys(array));console.log("length" in array);console.log(Object.keys(counter));console.log(Object.getOwnPropertyNames(Counter.prototype));
CheckResult

Results appear after mount.

Try it yourself

Arrays and classes are ordinary objects with carefully chosen property flags. The results are computed in your browser.

Array indexes are public enumerable keys; array length and class methods are not.

Where you’ll use this

These rules show up any time you copy, inspect, serialize, or loop over objects. Use Object.keys for ordinary public data. Use Object.hasOwn inside for...in if inherited keys would be a bug. Use descriptors when a copy must preserve hidden properties, symbols, getters, setters, or flags.

A complete own-property copy

Object.defineProperties(, Object.getOwnPropertyDescriptors(source)) copies every own descriptor. That is more precise than spread when hidden properties or symbols matter.

A very practical use is hiding a field from JSON without deleting it: make the property non-enumerable. The field still exists for code that knows the name, but JSON.stringify leaves it out.

Common misconceptions

“Object.keys shows all properties.”

It shows only own enumerable string keys. Symbols, hidden keys, and inherited keys are skipped.

“for...in is the same as Object.keys.”

for...in can include inherited enumerable string keys. Guard with Object.hasOwn when you only want own data.

“Non-enumerable means private.”

Non-enumerable only hides a property from certain lists. It is not a security boundary.

“Symbols are invisible.”

Symbols are skipped by many string-key APIs, but Object.getOwnPropertySymbols and Reflect.ownKeys find them.

“Object property order is random.”

Ordinary own-key readers follow the integer, string, symbol bucket rule you stepped through above.

Which reader answers which question?
APIOwn only?Enumerable only?Key types
Object.keysYesYesStrings
for...inNoYesStrings
Object.getOwnPropertyNamesYesNoStrings
Object.getOwnPropertySymbolsYesNoSymbols
Reflect.ownKeysYesNoStrings and symbols

Practice: predict the listing

5 EXERCISES
Exercise 1 · Warm-upPredict what each method lists

Predict the two printed lines. Type them as line one, a slash, then line two.

Starter codePop out in the code editor (opens in a new tab)JavaScript
const proto = { inherited: 1 };
const box = Object.create(proto);
box.visible = 2;
Object.defineProperty(box, "hidden", { value: 3 });
console.log(Object.keys(box).join(","));
const seen = [];
for (const key in box) seen.push(key);
console.log(seen.join(","));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeCopy everything own

    Which API pair copies the hidden string property and the symbol property?

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const id = Symbol("id");
    const source = { name: "Ada" };
    Object.defineProperty(source, "secret", { value: 7 });
    source[id] = 42;
    const copy = Object.defineProperties({}, Object.getOwnPropertyDescriptors(source));
    console.log(Reflect.ownKeys(copy).map(String).join(","));
    console.log(copy.secret);

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeExplain an inherited key

      Why does the loop print both keys?

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const proto = { inherited: "yes" };
      const child = Object.create(proto);
      child.own = "yes";
      const seen = [];
      for (const key in child) seen.push(key);
      console.log(seen.join(","));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · ChallengePredict key order

        Predict the exact line printed by Reflect.ownKeys.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const s = Symbol("s");
        const item = { "10": "ten", "2": "two", apple: 1 };
        item["01"] = "leading";
        item[s] = "symbol";
        console.log(Reflect.ownKeys(item).map(String).join("|"));

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeHide a property from JSON

          What JSON string prints after password becomes non-enumerable?

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const user = { name: "Ada", password: "secret" };
          Object.defineProperty(user, "password", { enumerable: false });
          console.log(JSON.stringify(user));
          console.log("password" in user);

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            7 QUESTIONS

            Every option explains itself, including the wrong ones.

            Lesson quiz · 7 questionsScore: first tries count
            1. Question 1 of 7Which two questions describe a property’s visibility?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does Object.keys print for the child object?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const proto = { inherited: 1 };
              const obj = Object.create(proto);
              obj.own = 2;
              console.log(Object.keys(obj).join(","));

              Choose an answer to see the explanation.

            3. Question 3 of 7Which API returns own string keys whether or not they are enumerable?

              Choose an answer to see the explanation.

            4. Question 4 of 7What does Object.keys print when the object also has a symbol?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const s = Symbol("id");
              const obj = { name: "Ada" };
              obj[s] = 1;
              console.log(Object.keys(obj).join(","));

              Choose an answer to see the explanation.

            5. Question 5 of 7Which method sees every own key: string and symbol, enumerable and non-enumerable?

              Choose an answer to see the explanation.

            6. Question 6 of 7What order does Reflect.ownKeys print for these string keys?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const obj = { "10": "ten", "2": "two", a: 1 };
              obj.b = 2;
              console.log(Reflect.ownKeys(obj).join("|"));

              Choose an answer to see the explanation.

            7. Question 7 of 7How can you hide a property from JSON.stringify without deleting it?

              Choose an answer to see the explanation.

            Key takeaways

            • Own properties live directly on the object; inherited properties are found through the prototype chain.
            • Enumerable properties are public to listing tools; non-enumerable properties still exist.
            • Object.keys means own, enumerable, string keys.
            • for...in means enumerable string keys, including inherited ones.
            • Reflect.ownKeys means every own key: strings and symbols, public and hidden.
            • Own-key order is integer-like strings, other strings, then symbols.

            Remember the one-liner.
            Choose a key-reading tool by ownership, enumerability, and key type.

            Up next: try, catch & finally.

            CompleteFrontend Clear concepts. Working examples.