What you'll be able to do

By the end of this page you should be able to explain how JavaScript looks up a property on an object, why [].map works but a plain object does not, and how constructor prototype links to instances.

Previous post: constructor functions.

Who this is for

  • People who asked "where does .map come from?" on an array
  • Beginners who saw __proto__ in DevTools and got nervous
  • Anyone connecting constructor functions to shared methods

You can skip this if prototype lookup is already clear. This is the bridge to class and to reading library source calmly.

Own properties vs inherited ones

const arr = [1, 2, 3];
console.log(arr.length);       // 3 — own property
console.log(typeof arr.map);   // function — found on Array.prototype

Scenario A — your object. user.name is usually own — stored directly on user.

Scenario B — built-in methods. arr.map is not copied onto every array; the engine walks a chain until it finds map on Array.prototype.

The rule: lookup checks the object first, then its prototype, then that prototype's prototype, until null.

The chain in one picture

const u = new User("Asha");
// u --> User.prototype --> Object.prototype --> null

Scenario A — instance method. u.save lives on User.prototype; u does not own save, but the chain finds it.

Scenario B — toString. Even empty objects inherit toString from Object.prototype unless you shadow it.

Where .map comes from

const nums = [10, 20];
nums.map((n) => n * 2); // [20, 40]

nums is an array instance. Its internal prototype link points to Array.prototype, where map lives. A plain object { 0: 10, 1: 20, length: 2 } is array-like but has no Array.prototype link — so no .map.

Scenario A — real array. Use .map directly.

Scenario B — NodeList from querySelectorAll. Borrow with Array.from(nodeList).map(...) or Array.prototype.map.call(nodeList, fn) — both rely on prototype / call ideas you already met.

Checking the chain safely

console.log(Object.getPrototypeOf(u) === User.prototype); // true
console.log(u.hasOwnProperty("name")); // true for own fields

Prefer Object.getPrototypeOf over __proto__ in new code — same idea, less surprise in interviews.

Scenario A — debugging "where did this method come from?" Log Object.getPrototypeOf(obj).

Scenario B — avoiding accidental shared state. If you mutate User.prototype.role = "guest", every instance sees it unless they have their own role.

A tiny practice file

<!DOCTYPE html>
<html>
  <body>
    <button id="go">Walk the chain</button>
    <pre id="out"></pre>
    <script>
      function Item(label) {
        this.label = label;
      }
      Item.prototype.describe = function () {
        return "Item: " + this.label;
      };
      const a = new Item("Pen");
      const out = document.getElementById("out");
      document.getElementById("go").addEventListener("click", function () {
        out.textContent =
          "own label: " + a.hasOwnProperty("label") + "\n" +
          "own describe: " + a.hasOwnProperty("describe") + "\n" +
          "via prototype: " + a.describe() + "\n" +
          "map on array: " + [1, 2].map((x) => x + 1).join(",");
      });
    </script>
  </body>
</html>

You should see describe found through the prototype, not as an own property.

Mistakes I see a lot

1. Thinking every object copies all methods. That would waste memory; the chain shares one map.

2. Using arr.map on array-like objects without converting. Length alone does not make an array.

3. Mutating built-in prototypes (Array.prototype.myHack = ...). Pollutes every array in the page — do not do this in apps.

4. Confusing prototype (on functions) with __proto__ / getPrototypeOf (on objects). Constructors have .prototype; instances link to that object.

What to try before the next post

  1. Log Object.getPrototypeOf([]) and compare to Array.prototype.
  2. Add a method on Item.prototype; confirm all instances see it.
  3. Build the tiny HTML file.

Next in this series: classes, extends, and super — the same model with cleaner syntax.

Try this next outside the series

These mental models become more useful when you can point at a real framework problem they explain.