JavaScript globalThis e l'oggetto globale
Scopri l'oggetto globale JavaScript: globalThis vs window vs global, cosa contiene, perché var e le funzioni di primo livello vi si aggiungono e come evitare di inquinare lo spazio dei nomi globale.
Ogni programma JavaScript viene eseguito all'interno di un oggetto di primo livello che esiste prima dell'avvio del codice: l'oggetto globale. Esso contiene i built-in del linguaggio (Array, Math, JSON, setTimeout e così via) e rappresenta la sede implicita di tutto ciò che si dichiara al livello più alto di uno script classico. Questa pagina spiega cos'è l'oggetto globale, come raggiungerlo in modo portabile con globalThis, cosa vi risiede effettivamente, perché alcune dichiarazioni di primo livello vi "trapelano" mentre altre no, e come tenere sotto controllo le proprie variabili globali.
Cos'è l'oggetto globale
L'oggetto globale è la radice della catena degli scope. Quando si fa riferimento a un nome che non viene trovato in nessuno scope di funzione o blocco circostante, il motore lo cerca infine come proprietà dell'oggetto globale. Ecco perché Math.max o JSON.parse funzionano ovunque — sono proprietà dell'oggetto globale che il runtime predispone automaticamente.
Ogni runtime espone quell'oggetto con un nome diverso, il che ha storicamente reso complicato scrivere codice cross-environment:
- I browser lo chiamano
window(e rendono disponibili ancheselfeframes). - I Web Worker lo chiamano
self(non esistewindowin un worker). - Node.js lo chiama
global.
globalThis: il globale portabile
Poiché il nome varia per ambiente, ES2020 ha introdotto globalThis — un unico riferimento standard che punta all'oggetto globale ovunque: browser, worker, Node.js, Deno e altro ancora. Ricorriti ogni volta che hai bisogno del vero oggetto globale in codice che deve essere eseguito in più ambienti.
console.log(typeof globalThis); // "object" in every environment
// Each of these is true only in its own environment:
// globalThis === window -> true in a browser tab
// globalThis === self -> true in a browser or a Web Worker
// globalThis === global -> true in Node.jsTentare di usare il nome sbagliato genera un ReferenceError, che è esattamente il problema che globalThis risolve:
Per un quadro più ampio di ciò che un ambiente host aggiunge al linguaggio, consulta l'ambiente browser e le specifiche.
Cosa si trova sull'oggetto globale
L'oggetto globale ospita due tipi di elementi:
- Built-in del linguaggio, definiti dalla specifica ECMAScript e presenti ovunque:
Object,Array,Function,String,Number,Boolean,Symbol,BigInt,Math,JSON,Date,RegExp,Promise,Map,Set, i costruttori degli errori e le funzioni globali comeparseInt,isNaNeeval. - API host (dell'ambiente), aggiunte dal runtime:
document,fetch,localStorage,setTimeoutealertnel browser;process,Buffererequirein Node.js.
// Built-ins are reachable through the global object:
console.log(globalThis.Math.max(2, 7, 4)); // 7
console.log(globalThis.JSON.stringify({ ok: true })); // {"ok":true}Perché var e le funzioni di primo livello vi trapelano
In uno script browser classico (non modulo), un var dichiarato al livello più alto e una dichiarazione function di primo livello diventano entrambi proprietà di window. Questo è un comportamento legacy incorporato nel linguaggio per compatibilità con le versioni precedenti:
// In a classic browser script (not a module):
var greeting = 'hi';
function greet() { return greeting; }
console.log(window.greeting); // "hi"
console.log(typeof window.greet); // "function"Le dichiarazioni con scope di blocco si comportano diversamente. let, const e class al livello più alto creano binding globali ma non si collegano all'oggetto globale:
let count = 1;
const name = 'app';
console.log(window.count); // undefined
console.log(window.name); // "" — note: window.name is a pre-existing browser property, not your variableDue avvertenze importanti:
- I moduli ES non trapelano affatto. Le dichiarazioni
varefunctiondi primo livello all'interno di un<script type="module">(o qualsiasi file conimport/export) hanno scope di modulo, quindi nulla — nemmenovar— si aggancia all'oggetto globale. - Anche i file Node.js sono moduli. Un
vardi primo livello in un file Node.jsha scope nel modulo, quindi non si aggancia aglobalcome farebbe uno script browser classico.
Questa differenza è uno dei motivi pratici per cui il codice moderno preferisce let/const e i moduli. Per la storia completa di hoisting e scoping relativa a var, leggi il vecchio "var" e scope delle variabili e closure.
Evitare l'inquinamento globale
Le variabili globali sono stato condiviso e mutabile: qualsiasi script può sovrascriverle, e le collisioni di nomi causano bug difficili da tracciare. Alcune abitudini mantengono il namespace pulito:
- Preferire
let/conste i moduli. Tengono le dichiarazioni completamente fuori dall'oggetto globale. - Usare un unico namespace quando si ha realmente bisogno di un globale, in modo da aggiungere una sola proprietà anziché molte.
- Attivare la strict mode.
"use strict"fa sì che un'assegnazione non dichiarata comex = 5generi un errore anziché creare silenziosamente un globale.
I moduli ES mantengono pulito il namespace globale
I moduli ES suddividono il codice in file riutilizzabili le cui dichiarazioni di primo livello rimangono private a ciascun file a meno che non vengano esportate esplicitamente. Questa è l'alternativa moderna all'aggiungere cose all'oggetto globale:
// file: math.js
export const add = (a, b) => a + b;
// file: app.js
import { add } from './math.js';
console.log(add(2, 3)); // 5
// `add` is imported, not read from a global — nothing leaks onto window/global.Conclusione
L'oggetto globale è lo scope radice del runtime: ospita i built-in del linguaggio e le API host, e negli script classici raccoglie anche le dichiarazioni var e function di primo livello. Usa globalThis per raggiungerlo in modo portabile, affidati a let/const e ai moduli per evitare di inquinarlo, e abilita la strict mode per intercettare i globali accidentali fin dall'inizio.