|
| 1 | + |
| 2 | + |
| 3 | +# Global object |
| 4 | + |
| 5 | +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. |
| 6 | + |
| 7 | +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 too its place. |
| 8 | + |
| 9 | +But the global object still remains in the specification. |
| 10 | + |
| 11 | +In a browser it is named "window", for Node.JS it is "global", for other environments it may have another name. |
| 12 | + |
| 13 | +It does two things: |
| 14 | + |
| 15 | +1. Provides access to built-in functions and values, defined by the specification and the environment. |
| 16 | + For instance, we can call `alert` directly or as a method of `window`: |
| 17 | + |
| 18 | + ```js run |
| 19 | + alert("Hello"); |
| 20 | + |
| 21 | + // the same as |
| 22 | + window.alert("Hello"); |
| 23 | + ``` |
| 24 | + |
| 25 | + The same applies to other built-ins. E.g. we can use `window.Array` instead of `Array`. |
| 26 | + |
| 27 | +2. Provides access to global Function Declarations and `var` variables. We can read them and write using its properties, for instance: |
| 28 | + |
| 29 | + <!-- no-strict to move variables out of eval --> |
| 30 | + ```js untrusted run no-strict refresh |
| 31 | + var phrase = "Hello"; |
| 32 | +
|
| 33 | + function sayHi() { |
| 34 | + alert(phrase); |
| 35 | + } |
| 36 | +
|
| 37 | + // can read from window |
| 38 | + alert( window.phrase ); // Hello (global var) |
| 39 | + alert( window.sayHi ); // function (global function declaration) |
| 40 | +
|
| 41 | + // can write to window (creates a new sglobal variable) |
| 42 | + window.test = 5; |
| 43 | +
|
| 44 | + alert(test); // 5 |
| 45 | + ``` |
| 46 | + |
| 47 | +...But the global object does not have variables declared with `let/const`! |
| 48 | + |
| 49 | +```js untrusted run no-strict refresh |
| 50 | +*!*let*/!* user = "John"; |
| 51 | +alert(user); // John |
| 52 | +
|
| 53 | +alert(window.user); // undefined, don't have let |
| 54 | +alert("user" in window); // false |
| 55 | +``` |
| 56 | + |
| 57 | +```smart header="The global object is not a global Environment Record" |
| 58 | +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). |
| 59 | + |
| 60 | +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 global variables. |
| 61 | + |
| 62 | +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. |
| 63 | + |
| 64 | +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. |
| 65 | +``` |
| 66 | +
|
| 67 | +## Uses of "window" |
| 68 | +
|
| 69 | +In server-side environments like Node.JS, the `global` object is used exceptionally rarely. Probably it would be fair to say "never". |
| 70 | +
|
| 71 | +In-browser `window` is sometimes used though. |
| 72 | +
|
| 73 | +Usually, it's not a good idea to use it, but here are some examples you can meet. |
| 74 | + |
| 75 | +1. To access exactly the global variable if the function has the local one with the same name. |
| 76 | + |
| 77 | + ```js untrusted run no-strict refresh |
| 78 | + var user = "Global"; |
| 79 | + |
| 80 | + function sayHi() { |
| 81 | + var user = "Local"; |
| 82 | + |
| 83 | + *!* |
| 84 | + alert(window.user); // Global |
| 85 | + */!* |
| 86 | + } |
| 87 | + |
| 88 | + sayHi(); |
| 89 | + ``` |
| 90 | + |
| 91 | + 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. |
| 92 | + |
| 93 | +2. To check if a certain global variable or a builtin exists. |
| 94 | + |
| 95 | + For instance, we want to check whether a global function `XMLHttpRequest` exists. |
| 96 | + |
| 97 | + We can't write `if (XMLHttpRequest)`, because if there's no `XMLHttpRequest`, there will be an error (variable not defined). |
| 98 | + |
| 99 | + But we can read it from `window.XMLHttpRequest`: |
| 100 | + |
| 101 | + ```js run |
| 102 | + if (window.XMLHttpRequest) { |
| 103 | + alert('XMLHttpRequest exists!') |
| 104 | + } |
| 105 | + ``` |
| 106 | + |
| 107 | + 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. |
| 108 | + |
| 109 | + We can also write the test without `window`: |
| 110 | + |
| 111 | + ```js |
| 112 | + if (typeof XMLHttpRequest == 'function') { |
| 113 | + /* is there a function XMLHttpRequest? */ |
| 114 | + } |
| 115 | + ``` |
| 116 | + |
| 117 | + This doesn't use `window`, but is (theoretically) less reliable, because `typeof` may use a local XMLHttpRequest, and we want the global one. |
| 118 | +
|
| 119 | +
|
| 120 | +3. To take the variable from the right window. That's probably the most valid use case. |
| 121 | + |
| 122 | + 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. |
| 123 | + |
| 124 | + That use is a little bit beyound our scope for now, but it looks like: |
| 125 | + ```html run |
| 126 | + <iframe src="/" id="iframe"></iframe> |
| 127 | +
|
| 128 | + <script> |
| 129 | + alert( innerWidth ); // get innerWidth property of the current window (browser only) |
| 130 | + alert( Array ); // get Array of the current window (javascript core builtin) |
| 131 | +
|
| 132 | + // when the iframe loads... |
| 133 | + iframe.onload = function() { |
| 134 | + // get width of the iframe window |
| 135 | + *!* |
| 136 | + alert( iframe.contentWindow.innerWidth ); |
| 137 | + */!* |
| 138 | + // get the builtin Array from the iframe window |
| 139 | + *!* |
| 140 | + alert( iframe.contentWindow.Array ); |
| 141 | + */!* |
| 142 | + }; |
| 143 | + </script> |
| 144 | + ``` |
| 145 | + |
| 146 | + 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. |
| 147 | + |
| 148 | +## "this" and global object |
| 149 | + |
| 150 | +Sometimes, the value of `this` is exactly the global object. That's rarely used, but some scripts rely on that. |
| 151 | +
|
| 152 | +1. In the browser, the value of `this` in the global area is `window`: |
| 153 | +
|
| 154 | + ```js run |
| 155 | + // outside of functions |
| 156 | + alert( this === window ); // true |
| 157 | + ``` |
| 158 | +
|
| 159 | + Other, non-browser environments, may use another value for `this` in such cases. |
| 160 | +
|
| 161 | +2. When a function with `this` is called in not-strict mode, it gets the global object as `this`: |
| 162 | + ```js run no-strict |
| 163 | + // not in strict mode (!) |
| 164 | + function f() { |
| 165 | + alert(this); // [object Window] |
| 166 | + } |
| 167 | +
|
| 168 | + f(); // called without an object |
| 169 | + ``` |
| 170 | +
|
| 171 | + 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`. |
0 commit comments