en.javascript.info/1-js/06-advanced-functions/05-global-object/article.md
Thierry Parmentelat 27a491f265 today’s typos
2017-05-11 20:41:00 +02:00

171 lines
6.4 KiB
Markdown

# Global object
When JavaScript was created, there was an idea of a "global object" that provides all global variables and functions. It was planned that multiple in-browser scripts would use that single global object and share variables through it.
Since then, JavaScript greatly evolved, and that idea of linking code through global variables became much less appealing. In modern JavaScript, the concept of modules took its place.
But the global object still remains in the specification.
In a browser it is named "window", for Node.JS it is "global", for other environments it may have another name.
It does two things:
1. Provides access to built-in functions and values, defined by the specification and the environment.
For instance, we can call `alert` directly or as a method of `window`:
```js run
alert("Hello");
// the same as
window.alert("Hello");
```
The same applies to other built-ins. E.g. we can use `window.Array` instead of `Array`.
2. Provides access to global Function Declarations and `var` variables. We can read and write them using its properties, for instance:
<!-- no-strict to move variables out of eval -->
```js untrusted run no-strict refresh
var phrase = "Hello";
function sayHi() {
alert(phrase);
}
// can read from window
alert( window.phrase ); // Hello (global var)
alert( window.sayHi ); // function (global function declaration)
// can write to window (creates a new global variable)
window.test = 5;
alert(test); // 5
```
...But the global object does not have variables declared with `let/const`!
```js untrusted run no-strict refresh
*!*let*/!* user = "John";
alert(user); // John
alert(window.user); // undefined, don't have let
alert("user" in window); // false
```
```smart header="The global object is not a global Environment Record"
In versions of ECMAScript prior to ES-2015, there were no `let/const` variables, only `var`. And global object was used as a global Environment Record (wordings were a bit different, but that's the gist).
But starting from ES-2015, these entities are split apart. There's a global Lexical Environment with its Environment Record. And there's a global object that provides *some* of the global variables.
As a practical difference, global `let/const` variables are definitively properties of the global Environment Record, but they do not exist in the global object.
Naturally, that's because the idea of a global object as a way to access "all global things" comes from ancient times. Nowadays is not considered to be a good thing. Modern language features like `let/const` do not make friends with it, but old ones are still compatible.
```
## Uses of "window"
In server-side environments like Node.JS, the `global` object is used exceptionally rarely. Probably it would be fair to say "never".
In-browser `window` is sometimes used though.
Usually, it's not a good idea to use it, but here are some examples you can meet.
1. To access exactly the global variable if the function has the local one with the same name.
```js untrusted run no-strict refresh
var user = "Global";
function sayHi() {
var user = "Local";
*!*
alert(window.user); // Global
*/!*
}
sayHi();
```
Such use is a workaround. Would be better to name variables differently, that won't require use to write the code it this way. And please note `"var"` before `user`. The trick doesn't work with `let` variables.
2. To check if a certain global variable or a builtin exists.
For instance, we want to check whether a global function `XMLHttpRequest` exists.
We can't write `if (XMLHttpRequest)`, because if there's no `XMLHttpRequest`, there will be an error (variable not defined).
But we can read it from `window.XMLHttpRequest`:
```js run
if (window.XMLHttpRequest) {
alert('XMLHttpRequest exists!')
}
```
If there is no such global function then `window.XMLHttpRequest` is just a non-existing object property. That's `undefined`, no error, so it works.
We can also write the test without `window`:
```js
if (typeof XMLHttpRequest == 'function') {
/* is there a function XMLHttpRequest? */
}
```
This doesn't use `window`, but is (theoretically) less reliable, because `typeof` may use a local XMLHttpRequest, and we want the global one.
3. To take the variable from the right window. That's probably the most valid use case.
A browser may open multiple windows and tabs. A window may also embed another one in `<iframe>`. Every browser window has its own `window` object and global variables. JavaScript allows windows that come from the same site (same protocol, host, port) to access variables from each other.
That use is a little bit beyond our scope for now, but it looks like:
```html run
<iframe src="/" id="iframe"></iframe>
<script>
alert( innerWidth ); // get innerWidth property of the current window (browser only)
alert( Array ); // get Array of the current window (javascript core builtin)
// when the iframe loads...
iframe.onload = function() {
// get width of the iframe window
*!*
alert( iframe.contentWindow.innerWidth );
*/!*
// get the builtin Array from the iframe window
*!*
alert( iframe.contentWindow.Array );
*/!*
};
</script>
```
Here, first two alerts use the current window, and the latter two take variables from `iframe` window. Can be any variables if `iframe` originates from the same protocol/host/port.
## "this" and global object
Sometimes, the value of `this` is exactly the global object. That's rarely used, but some scripts rely on that.
1. In the browser, the value of `this` in the global area is `window`:
```js run
// outside of functions
alert( this === window ); // true
```
Other, non-browser environments, may use another value for `this` in such cases.
2. When a function with `this` is called in non-strict mode, it gets the global object as `this`:
```js run no-strict
// not in strict mode (!)
function f() {
alert(this); // [object Window]
}
f(); // called without an object
```
By specification, `this` in this case must be the global object, even in non-browser environments like Node.JS. That's for compatibility with old scripts, in strict mode `this` would be `undefined`.