JavaScript policy on global variables / the global namespace
Asked Answered
S

1

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'
> 
Surpass answered 11/12, 2019 at 12:6 Comment(4)
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.Agriculture
Thanks. What I want to know is there any kind of guarantee that list won't increase over time.Surpass
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...".Agriculture
Related: Why is the variable closed being logged as false, if I define it globally as 0?. 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?Stupefacient
B
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.

Banneret answered 21/6, 2020 at 5:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.