JavaScript has multiple kinds of globals. There are at least:
- Globals that are inherited properties of the global object.
- Globals that are own properties of the global object; this includes the built-in globals.
- Globals that aren't properties of the global object.
(Those are in order, so if the same name is used at all three levels, the one you get when you use the identifier at global scope will be the one from #3.)
For example:
var theVar;
let theLet;
const hasOwn = Object.prototype.hasOwnProperty;
// On browsers, a global created because an element has an `id` (or in some cases
// `name`) is an inherited property of the global object (note that IE and Legacy
// Edge have older behavior)
console.log("theDiv:");
console.log("theDiv" in this); // true
console.log(hasOwn.call(this, "theDiv")); // false
// `var` at global scope creates an "own" property of the global object
console.log("theVar:");
console.log("theVar" in this); // true
console.log(hasOwn.call(this, "theVar")); // true
// `let`, `const`, and `class` declarations at global scope create globals that
// are not properties of the global object
console.log("theLet:");
console.log("theLet" in this); // false
console.log(hasOwn.call(this, "theLet")); // false
// The built-in globals are own properties of the global object:
console.log("Array:");
console.log("Array" in this); // true
console.log(hasOwn.call(this, "Array")); // true
console.log("undefined:");
console.log("undefined" in this); // true
console.log(hasOwn.call(this, "undefined")); // true
// Here's an exmaple of the fact that when the same name is used at all levels,
// the inner most (`let` in this case) wins:
const div = document.createElement("div");
div.id = "example";
document.body.appendChild(div); // Inherited global because of `id`
this.example = "own example"; // Global that's an own property
let example = "let example"; // Global created via `let`
console.log("Priority:");
console.log(example === "let example"); // true, innermost wins
.as-console-wrapper {
max-height: 100% !important;
}
<div id="theDiv"></div>
<div id="example"></div>
With the stage set...
I have read lots of articles and would find it helpful to discuss the points I've listed here. If it's too long for one question I'll split them up and re-post but since they're related, and not long, I thought it'd make sense putting them into one.
1.
First task is to define what happens when something's in the global scope.
From this I gather when something's in the global scope, it can be accessed at any point in any .js file.
Any JavaScript code running in the same realm, yes. Web workers are an example of JavaScript code related to your page but running in a separate realm. Similarly, the global environments of different tabs are in different realms, even when they can access each other (for instance, a parent window accessing a child window).
Looking at this page
The term "global objects" (or standard built-in objects) here is not
to be confused with the global object. Here, "global objects" refer to
objects in the global scope.
I interpret that to mean built-in objects are in the global scope (as defined above).
Yes. JavaScript's own globals are "own" properties of the global object. For example, you can see in the spec that the Array
constructor is explicitly listed as being a property of the global object.
The global object itself can be accessed using the this operator in
the global scope....
That's only mostly true. The host environment determines what this
is at global scope. On browsers, it's a proxy for the global object rather than actually the global object itself (more in the HTML spec), but you mostly don't need to care about that.
...In fact, the global scope consists of the properties
of the global object, including inherited properties, if any.
This last sentence almost threatened my understanding. Can I confirm the global scope doesn't consist entirely of the properties of the global object?
Correct, not only those properties. Those properties plus other things.
...Because the preceding paragraph said in-built objects were also in the global scope and they are not properties of the global object.
I don't see where the paragraph says they aren't properties of the global object.
Other objects in the global scope are either created by the user
script or provided by the host application. The host objects available
in browser contexts are documented in the API reference.
When I connect my .js file to my .html file it connects it to the DOM API which enables window
(the global object) to be in the global scope. Is this true?
The browser determines what this
is at global scope (it's that proxy for the global object), and also creates a property called window
on the global object that matches what this
is at global scope.
this mentions global variables. What are global variables? MDN says, in browsers, all global variables are members of the global object.
I previously thought a global variable is just another word for a property of the global object (whether you're in a browser or node.js
).
That used to be true, or at least mostly true (I wouldn't guarantee there weren't exceptions). It isn't anymore, as of ES2015, which introduced globals that are not connected to the global object (let
, const
, and class
declarations at global scope).
In the comments the question of whether the global object inherits from a prototype comes up. The answer is: it depends on the host environment, but in the environments I've seen, absolutely, yes. In fact, there are often multiple layers. You can see that using Object.getPrototypeOf
and Object.prototype.toString
to see if they given special names in the toString
tag:
const toString = Object.prototype.toString;
let obj = this;
let description = "global `this`";
while (obj) {
console.log(`${description} (${toString.call(obj)})`);
obj = Object.getPrototypeOf(obj);
description = "prototype of " + description;
}
(Snippets are having trouble today; here's a fiddle: https://jsfiddle.net/tjcrowder/zm1fhsve/)