completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Realms, globals & WindowProxy

Understand browser realms, iframe globals, WindowProxy, cross-realm values, same-origin access, and safe data transfer between windows.

By the end, you can
  • 01
    See that each frame has its own realmExplain why an iframe has its own built-ins, such as Array, Object, and Function.
  • 02
    Pick an array check that works across framesExplain why instanceof can give false for an array from a frame, and when to use Array.isArray instead.
  • 03
    Send data between frames on purposeChoose between reading a same-origin frame directly, postMessage, a copy (structured clone), or a transfer.

Each page gets its own realm

A web page can hold more than one place where JavaScript runs. The page itself is one. Each iframe is another. An iframe is a small page shown inside a bigger page, such as a video player or a payment form.

Each of these places has its own realm. A realm is one complete JavaScript world. It has:

  • a global object: the object that holds all the global names. In a page it is window, and you can always reach it as globalThis;
  • its own built-ins: the ready-made objects JavaScript gives you, such as Array, Object, and Function.
Definition

A realm is one JavaScript world: one global object plus its own set of built-ins. The top page, each iframe, and each worker (a script that runs in the background, apart from the page) usually get a realm of their own.

Store a name on the global object and read it backPop out in the code editor (opens in a new tab)JavaScript
globalThis.lessonName = "realms";console.log(globalThis.lessonName);

Line 1 stores a property called lessonName on this realm's global object. Line 2 reads it back and prints realms. An iframe has a different global object, so it does not get this property.

Two global objects keep their own namesPop out in the code editor (opens in a new tab)JavaScript
globalThis.cartName = "parent cart";const frameGlobal = { cartName: "frame cart" }; console.log(globalThis.cartName);console.log(frameGlobal.cartName); // A real iframe has its own global object. This plain object only stands in for it.

Line 1 stores cartName on the page's global object. Line 2 makes a plain object, frameGlobal. It stands in for an iframe's global object, so the example can run here. Line 4 prints parent cart. Line 5 prints frame cart. In a real browser, an iframe gives you a second global object like this.

Two windows. The page has a box called cartName holding parent cart. The iframe has its own box called cartName holding frame cart.page"parent cart"cartNamethe page's global objectiframe"frame cart"cartNamethe iframe's global object
The page and the iframe each have their own global object. Setting cartName in one does not set it in the other.

So realms are kept apart. A name you put on one global object does not show up in another frame. Frames can still work together, but only on purpose. There are two ways, and you will see both later:

  • reach into the other frame directly, which is allowed only when both pages come from the same site;
  • send the other frame a message.

You may read about ShadowRealm. It is a proposal: a suggested new JavaScript feature that the standards group, TC39, is still discussing. Browsers don't ship it yet, so this lesson does not use it. An iframe is a real realm in browsers today. It also has its own page and its own address rules, which ShadowRealm would not have.

Realms matter when a page puts something inside an iframe: a checkout, a code editor, a preview, or an older app. Each frame runs normal JavaScript. But each frame has its own built-ins and its own global names. The previous lesson, Bindings: how DOM objects exist in JavaScript, shows how browser objects appear inside one realm.

The table below lists four words this lesson uses. Read each row as: the word, what it means, and an example.

Four words for the parts of a realm
WordWhat it meansExample
RealmOne JavaScript world: a global object plus its own built-ins.The top page, each iframe, and each worker get their own realm.
Global objectThe object that holds all the global names of one realm.In a page, it is the window object.
WindowProxyWhat you get when you save a frame's window. It always reaches the page the frame shows now.After the frame loads a new page, it passes requests on to the new page's Window.
IntrinsicThe spec's word for one of a realm's built-ins.Each frame gets its own Array, Object, Function, and Promise.

Each iframe has its own built-ins

The spec (the official rule book for JavaScript and the web) calls a realm's built-ins its intrinsics. They include the constructors, such as Array. A constructor is a function that makes new objects.

Each constructor has a prototype. A prototype is a shared object that every value the constructor makes links back to. For Array, it is Array.prototype, where methods like push live.

The page's Array and an iframe's Array do the same job. But they are two different objects.

Make an array with the iframe's ArrayJavaScript
const frame = document.createElement("iframe");document.body.append(frame); const FrameArray = frame.contentWindow.Array;const list = new FrameArray("tea"); console.log(list instanceof Array);console.log(Array.isArray(list));

Line 1 makes an empty iframe. Line 2 adds it to the page, so the iframe gets its own window. frame.contentWindow is that window. Line 4 reads the iframe's Array. Line 5 uses it to make a list. Line 7 prints false. Line 8 prints true.

A list made by the iframe's Array. The page asks two questions. list instanceof Array gives false. Array.isArray(list) gives true.listmade by theiframe's Arraylist instanceof ArrayfalseArray.isArray(list)true
instanceof looks for the page's own Array, so it gives false. Array.isArray only asks whether list is an array, so it gives true.

Why false? list instanceof Array asks: "Does list link back to this page's Array.prototype?" It does not. It links back to the iframe's Array.prototype.

Array.isArray(list) asks a different question: "Is this value an array at all?" The answer is the same in every realm.

Try this example in the console of a normal page you control. It will not work in this lesson's editor. The editor runs your code in a locked-down frame with no site address of its own. That frame may not read even an empty iframe's contentWindow.Array, so it throws a SecurityError.

Real-life analogySeparate classrooms

Each iframe is like a separate classroom with its own copy of the same textbook. A page torn from class A's book did not come from class B's book, even when the words are exactly the same.

In real life: Each classroom has its own copy of the textbook
In JavaScript: Each realm has its own Array and Object
In real life: A torn-out page came from one classroom's book
In JavaScript: A value links back to the realm that made it
In real life: The words in both books match
In JavaScript: The built-ins in both realms look the same
In real life: The books still belong to different classrooms
In JavaScript: instanceof sees two different Array constructors

WindowProxy: a reference that survives a new page

A frame can load a new page. This is called navigation. Each new page gets a fresh global object, a new Window.

So what do you hold when you save frame.contentWindow? Not the Window itself. You hold a WindowProxy. A WindowProxy is a stand-in that passes each request on to whatever page the frame shows right now.

The spec calls the frame itself a browsing context: the place that shows one page at a time. The names contentWindow, parent, and frames all give you a WindowProxy.

A saved frame reference stays the same after a new page loadsJavaScript
const frame = document.querySelector("iframe");const room = frame.contentWindow; console.log(room === frame.contentWindow);frame.src = "/next-page";console.log(room === frame.contentWindow);

Line 2 saves the frame's window in room. Line 4 prints true. Line 5 sets frame.src, which starts loading a new page. Line 6 prints true again, even before the new page has finished loading. This example is for reading only, because this lesson has no /next-page to load.

Left, before line 5: a tag called room points at the iframe, which shows the first page. Right, after line 5: the same room tag points at the same iframe, which now shows /next-page.before line 5roomiframefirst pageafter line 5roomiframe/next-page
room points at the iframe itself, not at one page inside it. After line 5 loads a new page, room reaches the new page.

The main idea: room stays useful while the page inside the frame, and its Window, change.

Real-life analogyThe reception desk

Think of a school reception desk. You always call the desk, and the desk puts you through to whoever teaches in that room today. When a new teacher takes over the room, the same desk number still works.

In real life: You call the reception desk
In JavaScript: Your code uses a WindowProxy
In real life: A new teacher takes over the room
In JavaScript: Navigation creates a new Window
In real life: The desk puts your call through
In JavaScript: The WindowProxy passes each request on
In real life: The same desk number still works
In JavaScript: A saved contentWindow still works

Four realm names the spec uses

Sometimes the spec must pick one realm out of several. For example: when a page calls a function from a frame, whose settings apply? The HTML spec has four names for this. They solve rare edge cases. Most of the time you only need two of them: current and relevant.

A page calls a method from a frameJavaScript
const frame = document.querySelector("iframe");const printInFrame = frame.contentWindow.print;printInFrame.call(frame.contentWindow);

Line 1 finds a frame. Line 2 reads the frame's print method. Line 3 calls it with .call(frame.contentWindow). .call() runs a function and sets the object it works on (its this). Here that object is the frame's window.

This one short call already involves two realms: the page's and the frame's. The four names below let the spec say exactly which one it means.

  • Entry realm: the realm of the script that started the work that is running now.
  • Incumbent realm: the realm of the page code that ran most recently, or that set up the callback running now. A callback is a function you hand over to be called later.
  • Current realm: the realm of the function running right now.
  • Relevant realm: the realm a browser object belongs to, usually the realm that made it.

For example, a method called on a frame's DOM object usually uses that object's relevant realm, which is the frame's realm. The spec writers tell new specs to avoid entry and incumbent where they can. Those two depend on the history of calls and callbacks, which is hard to follow.

The four names as plain notesPop out in the code editor (opens in a new tab)JavaScript
const callback = {  entry: "the script that began this work",  incumbent: "the author code that scheduled it",  current: "the function running now",  relevant: "the realm of the platform object",}; console.log(callback.current);console.log(callback.relevant); // These notes only help you remember the names. They don't read real realms.

Lines 1 to 6 store one short note for each name. Line 8 prints the function running now. Line 9 prints the realm of the platform object. "Platform object" is the spec's word for a browser object, such as an element.

This is not a browser feature that shows hidden realms. It is only a way to keep the four names apart while you read a spec.

When your code calls a method, start with the object you call it on. A DOM node that belongs to a frame brings its relevant realm along. The current realm is simply the realm of the function that is running at that moment.

Why instanceof fails for a frame's array

A cross-realm object is a value made in one realm and used in another. Arrays show this best. Both realms have a name Array, but the two names point to different constructor objects.

Compare a page array with a frame arrayJavaScript
const frame = document.createElement("iframe");document.body.append(frame);const FrameArray = frame.contentWindow.Array;const parentArray = ["tea"];const frameArray = new FrameArray("tea"); console.log(parentArray instanceof Array);console.log(frameArray instanceof Array);console.log(Array.isArray(frameArray));

Lines 1 to 3 make an iframe and read its Array. Line 4 makes a normal page array. Line 5 makes a frame array.

  • Line 7 prints true, because the page made that array.
  • Line 8 prints false, because the frame made that array.
  • Line 9 prints true, because Array.isArray works across realms.

This does not mean instanceof is broken. It checks whether a value links back to one exact prototype. That is useful when you really mean "made by this exact constructor". When you only need to know "is this an array?" and the value may come from another realm, use Array.isArray.

Step through: instanceof and Array.isArray on a stand-in array
Step 0 of 5Ready
Your turn: follow the blue line

This replays the lesson code step by step. It shows the results you can see, not the engine's inner workings.

Running in
  1. script
Next: line 1
Object.setPrototypeOf(frameArray, null); const parentThinksItIsAnArray = frameArray instanceof Array;const parentRecognizesAnArray = Array.isArray(frameArray); console.log(parentThinksItIsAnArray);console.log(parentRecognizesAnArray);
CallStoreChangeResultBlue line: runs next. 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.

The step-through can't use a real iframe, so it uses a stand-in. Line 2 takes a normal array and removes its link to any prototype. Then instanceof gives false, and Array.isArray still gives true. A real iframe array links to the iframe's own prototype instead. To see that for real, run the earlier example in a normal page's console.

Compare two realms

The playground has two realms, the page and an iframe, and one array. Pick which realm makes the array. Then pick which realm's instanceof Array check runs. Reset goes back to the most useful case: the iframe makes the array, and the page checks it.

Playground: which realm makes the array, and which one checks it?
The two checksJavaScript
const frameArray = ["tea"];Object.setPrototypeOf(frameArray, null); const parentThinksItIsAnArray = frameArray instanceof Array;const parentRecognizesAnArray = Array.isArray(frameArray); console.log(parentThinksItIsAnArray);console.log(parentRecognizesAnArray);
Resultsmade in the iframe, checked in the page
instanceof Arrayfalse

Asks: does the array link back to this realm's own Array.prototype?

Array.isArraytrue

Asks only: is this value an array? The realm does not matter.

Try it yourself
Array made in
instanceof Array checked in

The array was made in the iframe, but instanceof looks for the Array of the page. Different realms, so it gives false. Array.isArray still gives true.

This is a small model of the instanceof result. The iframe code earlier in the lesson shows the same results with real realms.

Every choice gives true for Array.isArray. That is the point. "This value is an array" and "this value came from this realm's Array" are two different facts.

Reading another frame: same origin only

An origin is the start of a web address: the scheme, the host name, and the port. For example, https://shop.example is an origin.

The same-origin policy is the browser rule that decides when one page may read another page directly:

  • Frames from the same origin can read each other's page and JavaScript objects.
  • Frames from different origins (cross-origin) cannot read normal properties such as document. If you try, the browser throws a SecurityError.
Read the page inside a same-origin iframeJavaScript
const frame = document.createElement("iframe");frame.onload = () => {  console.log(frame.contentWindow.document.body.textContent);};frame.srcdoc = "<p>Same-origin frame</p>";document.body.append(frame);

Line 1 makes an iframe. Lines 2 to 4 set up an onload function, which runs once the frame's page has loaded. Line 5 sets srcdoc, which gives the frame its HTML directly as text. Line 6 adds the frame to the page.

When the frame loads, the function reads the frame's page text and prints Same-origin frame. This works because a srcdoc page counts as the same origin as your page. Try it in the console of a normal page you control. This lesson's editor is a locked-down frame and blocks reads from contentWindow.

Cross-origin windows still allow a few safe actions. A page can call postMessage on them. It can also set a cross-origin frame's location to send it to a new address. But it cannot look inside the other page. See Windows and frames for more on frames.

Send a message instead of reading a cross-origin frameJavaScript
const frame = document.querySelector("iframe"); window.addEventListener("message", (event) => {  console.log(event.data);}); frame.contentWindow.postMessage({ type: "cart", count: 3 }, "*");

postMessage sends a message to another window. The other window gets it as a message event. Line 3 starts listening for messages. Line 7 sends plain data to the frame.

The "*" at the end of line 7 means "any origin may receive this". In real code, put the receiver's exact origin there instead. When a message arrives, check event.origin (who sent it) and the shape of the data before you act on it.

Check a message before using itPop out in the code editor (opens in a new tab)JavaScript
const event = {  origin: "https://checkout.example",  data: { type: "order-ready", id: "tea-3" },}; const isExpected = event.origin === "https://checkout.example" && event.data.type === "order-ready";console.log(isExpected); // Check where a message came from and what it holds before you use it.

Lines 1 to 4 describe one message that arrived. Line 6 checks two things: the origin it came from, and its type. Line 7 prints true only for the expected checkout message. Real code should ignore a message from an unknown origin, or with unknown data, before it changes a cart or an account.

Copying and moving data between frames

Often a frame does not need to reach into another frame. It only needs to send data. There are two ways to send it:

  • Structured clone makes a full, separate copy of the data. Values it can copy are called serializable.
  • A transfer moves the data instead of copying it. Values that can be moved are called transferable.

postMessage uses structured clone for you. You can also call it yourself with structuredClone(value).

Copy plain data with structuredClonePop out in the code editor (opens in a new tab)JavaScript
const cart = { item: "tea", count: 3 };const copy = structuredClone(cart); copy.count = 4;console.log(cart.count);console.log(copy.count);

Line 1 makes the original cart. Line 2 copies it. Line 4 changes only the copy. Lines 5 and 6 print 3 then 4. So the two objects are separate.

Each side can change its own copyPop out in the code editor (opens in a new tab)JavaScript
const order = { id: "tea", count: 3 };const copy = structuredClone(order);copy.count = 4; console.log(order.count);console.log(copy.count); // The copy is a new object. It shares nothing with the original.

Line 1 makes an order. Line 2 makes the copy. Line 3 changes the copy. Lines 5 and 6 still print 3 then 4. A copy is useful when the sender and the receiver should each be free to change their own data.

Move an ArrayBuffer instead of copying itPop out in the code editor (opens in a new tab)JavaScript
const buffer = new ArrayBuffer(8);const moved = structuredClone(buffer, { transfer: [buffer] }); console.log(buffer.byteLength);console.log(moved.byteLength);

An ArrayBuffer is a block of raw bytes, such as the contents of a file. Its byteLength tells you how many bytes it holds.

  • Line 1 makes a buffer of 8 bytes.
  • Line 2 puts buffer in the transfer list, so its bytes move to moved.
  • Line 4 prints 0. The old buffer is now empty. The spec calls it detached.
  • Line 5 prints 8, because moved now holds the bytes.
structuredClone with a transfer list. The box called buffer is now empty, byteLength 0. The 8 bytes moved to the box called moved, byteLength 8.structuredClone(buffer, { transfer: [buffer] })bufferbyteLength 0bytes move8 bytesmovedbyteLength 8
The 8 bytes move into moved. The old buffer is left empty, so its byteLength is 0.
Step through: moving an ArrayBuffer
Step 0 of 4Ready
Your turn: follow the blue line

This replays the lesson code step by step. It shows what you can see when an ArrayBuffer is moved.

Running in
  1. script
Next: line 1
const moved = structuredClone(buffer, { transfer: [buffer] }); console.log(buffer.byteLength);console.log(moved.byteLength);
CallStoreChangeResultBlue line: runs next. 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.
A function cannot be copiedPop out in the code editor (opens in a new tab)JavaScript
const cart = { save() {} }; try {  structuredClone(cart);} catch (error) {  console.log(error.name);}

Line 1 makes an object that holds a function, save. Line 4 tries to copy it inside try. If the code in try fails, the catch part runs and gets the error. Line 6 prints the error's name, DataCloneError.

Functions and DOM nodes cannot be copied. A function is code, not plain data. A DOM node belongs to one page and only makes sense there.

The table below sums up the four cases. Read each row as: the case, what happens, and when to use it.

Four ways data can cross between frames
CaseWhat happensWhen to use it
Same originYour page can read the other frame's page and JavaScript objects directly.Use it for pages you own that must work closely together.
Different originYour page cannot read the other frame's page. Trying throws a SecurityError.Use postMessage with the receiver's exact origin.
SerializableStructured clone makes a separate copy.Use it for plain objects, arrays, maps, dates, and other plain data.
TransferableThe data moves. The sender's copy is left empty.Use it for an ArrayBuffer or a MessagePort.
Symbol.for gives the same symbol in every realmPop out in the code editor (opens in a new tab)JavaScript
const parentSymbol = Symbol.for("cart-status");const otherRealmSymbol = Symbol.for("cart-status"); console.log(parentSymbol === otherRealmSymbol); // Symbol.for uses one shared list, but each realm has its own Array.

A symbol is a unique value, often used as a property key. Symbol.for(key) looks up a symbol by name in the global symbol registry, a shared list of named symbols. Lines 1 and 2 ask that list for the same name. Line 4 prints true.

Remember this exception. Each realm has its own Array. But realms in the same agent share one symbol registry. An agent is the spec's name for one thread that runs JavaScript. A page and the frames it can read directly share one agent.

Choosing a safe way to connect frames

First ask: do these two pages really need to reach into each other? Same-origin pages can share objects directly. But then each page depends on the other page's inner details. A message makes the shared data easy to see, and it also works across origins.

A value may come from a browser extension, an iframe, or another window. Then don't check its type only with instanceof. Use checks that work in any realm: for example Array.isArray for arrays, a type property that you check by name, or a check of every field for messages you don't trust.

  • To talk across origins, use postMessage with the receiver's exact origin.
  • Before you use a message, check where it came from and the shape of its data.
  • Transfer a large buffer when only the receiver needs it. Copy the data when both sides need their own.
  • Use Array.isArray when an array may come from another realm.
Copy, move, or refuse?
  • A plain cart object with strings and numbers
  • A Map from product IDs to amounts
  • An ArrayBuffer listed in the transfer list
  • One end of a MessageChannel (a MessagePort)
  • A save function that remembers a cart
  • A button element from the page
Try it yourself
0 of 6 correct

Sort each value by what structured clone does with it. Read the explanation after each choice.

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

Common misconceptions

  • “An iframe is only something you see.” It also has its own page, its own global object, and its own realm.
  • “window is always one object.” A reference to another frame's window is usually a WindowProxy. It keeps working after the frame loads a new page.
  • “instanceof recognizes every array.” It checks one realm's Array.prototype. An array from another realm fails that check.
  • “Same origin means the frames share everything.” Same origin lets frames read each other directly. But their realms and their Array constructors are still separate.
  • “structuredClone can copy anything.” Functions and DOM nodes make it throw a DataCloneError.

The table below lists words that are easy to mix up. Read each row as: the word, what it means, and what it is not.

Words that are easy to mix up
WordWhat it meansWhat it is not
A realmOne JavaScript world: a global object plus its own built-ins.Not a browser tab, and not a program running on your computer.
WindowThe real global object of the page a frame shows.Not always the same object as a saved frame reference.
WindowProxyA saved frame reference that always reaches the page the frame shows now.Not a copy of the first page's Window that stays stuck on that page.
structuredCloneMakes a separate copy of plain data.Not a way to copy functions, DOM nodes, or the values a function remembers.

Practice exercises

Exercise 1 · Warm-upPick the array check

A product widget runs in an iframe and gives the page an array. Which check should the page use to recognize it as an array?

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

    Exercise 2 · Warm-upPredict a transferred buffer

    Read the program and type exactly what it prints.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const buffer = new ArrayBuffer(4);
    const moved = structuredClone(buffer, { transfer: [buffer] });
    console.log(buffer.byteLength, moved.byteLength);

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

      Exercise 3 · PracticeExplain the reference that keeps working

      A page saves frame.contentWindow. Then the frame loads a new page. Why does the saved reference still work?

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

        Exercise 4 · PracticeChoose the safe channel

        Your analytics iframe comes from a different origin. Which browser method should send it a small order summary?

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

          Exercise 5 · ChallengeName the copy error

          Your code calls structuredClone on an object that holds a function. What is the name of the error it throws?

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

            Exercise 6 · ChallengeApply it to a checkout

            A checkout runs in an iframe from a different origin. It must tell the page that an order is ready. How should it send that news?

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

              Check your understanding

              The quiz checks four things that are easy to mix up:

              • which realm made a value,
              • what a saved frame reference reaches,
              • whether two origins match,
              • whether data is copied or moved.
              Realms and globals quiz · 7 questionsScore: first tries count
              1. Question 1 of 7What does an iframe in a browser usually get for JavaScript?

                Choose an answer to see the explanation.

              2. Question 2 of 7Line 2 removes the array's link to any prototype, like an array from another realm. What does this print?

                Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                const list = ["tea"];
                Object.setPrototypeOf(list, null);
                console.log(list instanceof Array);
                console.log(Array.isArray(list));

                Choose an answer to see the explanation.

              3. Question 3 of 7What is a WindowProxy for?

                Choose an answer to see the explanation.

              4. Question 4 of 7Which two realm names do you need most often?

                Choose an answer to see the explanation.

              5. Question 5 of 7How should two frames from different origins send each other plain data?

                Choose an answer to see the explanation.

              6. Question 6 of 7What does the transfer code print?

                Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                const buffer = new ArrayBuffer(4);
                const moved = structuredClone(buffer, { transfer: [buffer] });
                console.log(buffer.byteLength, moved.byteLength);

                Choose an answer to see the explanation.

              7. Question 7 of 7Why does structuredClone({ save() {} }) throw?

                Choose an answer to see the explanation.

              Key takeaways

              • Every page and every iframe has its own realm: its own global object and its own built-ins.
              • A saved frame reference is a WindowProxy. It keeps working after the frame loads a new page.
              • For an array from another realm, instanceof Array is false, but Array.isArray is true.
              • Of the four realm names, you mostly need two: the current realm and an object's relevant realm.
              • Same-origin frames can read each other directly. Cross-origin frames should talk with postMessage.
              • Structured clone copies plain data. A transfer moves values such as an ArrayBuffer and leaves the old one empty.

              Remember the one-liner.
              A realm is one JavaScript world with its own global object, so an iframe's Array looks the same as yours but is a different object.

              Coming next: the browser security model. It shows how the same-origin policy and the browser's separate processes keep these worlds safe from each other.

              CompleteFrontend Clear concepts. Working examples.