6

Today I ran into an issue that top is a pre-existing global variable.

const left = 1;
const right = 2;
const top = 3;
const bottom = 4;
console.log(left, right, top, bottom);

result:

Uncaught SyntaxError: Identifier 'top' has already been declared

I think I've just been lucky until today that most of the time my usage of a variable called top was inside a function.

How much do I need to worry about browsers adding new global variables that will break code in the future? It seems like until es6 import pretty much all browser libraries used global variables unless they had a build step. But, looking at the top example it seems like browser could add new unsettable global variables at anytime and therefore they should be avoided at all costs. I see some variables things like HTMLElement are assignable.

console.log(HTMLElement);
HTMLElement = 'foo';
console.log(HTMLElement);

result:

function HTMLElement() { [native code] }
foo

Is top some legacy thing but browser specs promise not to do more of that in the future? Like I can't assign window

const window = 'foo';
console.log(window);

result:

SyntaxError: Identifier 'window' has already been declared

but I can assign process in node

Welcome to Node.js v12.6.0.
Type ".help" for more information.
> process
process {
  version: 'v12.6.0',
  versions: {
    node: '12.6.0',
 ...
}
> process = 'foo'
'foo'
> process
'foo'
> 
gman
  • 100,619
  • 31
  • 269
  • 393
  • 2
    Just as a complement, running `console.log(Object.entries(Object.getOwnPropertyDescriptors(window)).filter(d => !d[1].configurable).map(d => d[0]))` gives me this quite short list, considering the number of properties in the global object: `["document", "NaN", "window", "Infinity", "undefined", "location", "top"]`. Those are the property names that, used with `const`, will throw the error you described. – Gerardo Furtado Dec 11 '19 at 12:57
  • Thanks. What I want to know is there any kind of guarantee that list won't increase over time. – gman Dec 11 '19 at 13:03
  • Yes, sure, I understand your question (and that's why I wrote a comment, not an answer). I just found interesting that the list is not that long. Well, let's see if someone can answer your question, but I'm afraid the answer will be *"we can't know for sure..."*. – Gerardo Furtado Dec 11 '19 at 13:05
  • Related: [Why is the variable `closed` being logged as `false`, if I define it globally as `0`?](https://stackoverflow.com/a/51062916/4642212). In this answer, there’s a larger list of such non-configurable, non-writable, or setter properties. There’s a difference between using `var` vs. `let` or `const` in global scope — if assignment doesn’t throw an error, `const` or `let` actually creates the variable with the new value, as opposed to `var`. However, properties like `top`, `window` or `document` throw an error when assigning to them, but why _those_ and not e.g. `closed` or `history`? – Sebastian Simon Apr 06 '20 at 19:23

1 Answers1

2

How much do I need to worry about browsers adding new global variables that will break code in the future?

You shouldn't worry about it. New features for JS and HTML are tested extensively. Browsers will generally deploy code that watches for incompatibilities with planned APIs to determine if they will be safe to ship. (For example if a browser wants to add globalThis.foo, it might deploy a counter that increments every time code accesses or assigns to globalThis.foo to understand if it's already being used for something else). In addition, developer previews of browsers allow developers to catch possible issues before they get too far. You might find this interesting: https://developers.google.com/web/updates/2018/03/smooshgate.

All that being said, I still wouldn't suggest you go around creating lots of globals, it's not the most fantastic pattern.

Is top some legacy thing but browser specs promise not to do more of that in the future? Like I can't assign window

It is indeed legacy, though I don't know of any such promises. The HTML standard defines window.top as follows (from https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-window-object):

[LegacyUnforgeable] readonly attribute WindowProxy? top;

[LegacyUnforgeable] means the property top is created on window with the property attribute configurable set to false. Global declarations that shadow non-configurable properties will fail because they cannot change the value.

but I can assign process in node

This is because process in Node.js is a configurable property.

> Object.getOwnPropertyDescriptor(globalThis, 'process')
{
  get: [Function: get],
  set: [Function: set],
  enumerable: false,
  configurable: true
}

As a last note, there is a difference between assignments and declarations. You can still assign to non-configurable properties as long as they are writable or provide a setter.

user3840170
  • 26,597
  • 4
  • 30
  • 62
snek
  • 1,980
  • 1
  • 15
  • 29