Всюдусущий свидетель: Как работает глобальный объект в JavaScript (и почему его не любят)
Представьте, что у вас есть гигантская коробка. Вы можете положить в неё что угодно, и это что-то станет доступным отовсюду - из любой комнаты, любого ящика, любого уголка вашего кода. Эта коробка существует всегда. Она появляется вместе с программой и исчезает только когда программа завершается.
Это глобальный объект. Он всегда рядом. Он хранит console, setTimeout, Math и все ваши глобальные переменные. Но с великой силой приходит великая ответственность. Засорить глобальный объект - значит создать потенциальный ад для отладки.
Сегодня мы разберём, что такое глобальный объект, как к нему обращаться в разных средах, почему он опасен и как правильно с ним работать.
Часть 1. Что такое глобальный объект?
Глобальный объект - это объект, который всегда существует в глобальной области видимости. Его свойства доступны из любого места программы.
В браузере это window. В Node.js - global. В современных средах есть ещё globalThis, который работает везде.
javascript
// В браузере
console.log(window.console === console); // true
console.log(window.setTimeout === setTimeout); // true
// В Node.js
console.log(global.console === console); // true
console.log(global.setTimeout === setTimeout); // true
Что хранится в глобальном объекте?
- Встроенные объекты: Object, Array, Function, String, Number
- Функции: setTimeout, setInterval, console.log, parseInt
- Константы: NaN, Infinity, undefined
- Глобальные переменные, объявленные через var (в браузере)
Часть 2. Глобальный объект в разных средах
2.1 Браузер: window
В браузере глобальный объект называется window. Он также представляет окно браузера.
javascript
// Доступ к встроенным объектам
window.alert("Привет!");
window.document.title = "Новая страница";
// Глобальные переменные через var становятся свойствами window
var myVar = 42;
console.log(window.myVar); // 42
// Переменные через let/const НЕ становятся свойствами window
let myLet = 100;
console.log(window.myLet); // undefined
Специальные свойства window:
- window.innerWidth / innerHeight - размер окна
- window.location - URL текущей страницы
- window.history - история браузера
- window.localStorage / sessionStorage - хранилища
- window.document - DOM-дерево
2.2 Node.js: global
В Node.js глобальный объект называется global.
javascript
// Доступ к встроенным объектам
global.console.log("Привет!");
// Глобальные переменные
global.myVar = 42;
console.log(myVar); // 42
// Специфичные для Node.js
global.process.version; // версия Node.js
global.__dirname; // текущая директория
global.__filename; // текущий файл
2.3 Web Workers: self
В Web Workers глобальный объект называется self.
javascript
// В worker.js
self.onmessage = function(event) {
self.postMessage("Ответ: " + event.data);
};
self.console.log("Worker запущен");
2.4 Универсальный доступ: globalThis (ES2020)
globalThis работает везде: в браузере, Node.js, Web Workers.
javascript
// Один способ для всех сред
globalThis.console.log("Работает везде!");
// Создание универсальной глобальной переменной
globalThis.myApp = {
version: "1.0.0",
config: {}
};
// Теперь myApp доступен в любом месте
До появления globalThis приходилось писать такой костыль:
javascript
const getGlobal = () => {
if (typeof window !== "undefined") return window;
if (typeof global !== "undefined") return global;
if (typeof self !== "undefined") return self;
throw new Error("No global object found");
};
Часть 3. Создание глобальных переменных
3.1 Через объявление (только var и function)
javascript
// Становятся свойствами глобального объекта (в браузере)
var globalVar = 42;
function globalFunc() {}
console.log(window.globalVar); // 42
console.log(window.globalFunc); // function globalFunc() {}
3.2 Через присваивание свойству глобального объекта
javascript
// Явное добавление
window.myGlobal = "явное";
globalThis.myOther = "тоже явное";
// Опасно: случайное создание глобальной переменной
function oops() {
accidentalGlobal = "я глобальный"; // забыли var/let/const
}
oops();
console.log(window.accidentalGlobal); // "я глобальный"
3.3 let и const НЕ становятся свойствами глобального объекта
javascript
let letVar = 42;
const constVar = 100;
console.log(window.letVar); // undefined
console.log(window.constVar); // undefined
// Но они всё равно в глобальной области видимости
console.log(letVar); // 42
console.log(constVar); // 100
Часть 4. Почему глобальные переменные - это плохо?
4.1 Конфликт имён (коллизия)
javascript
// Библиотека A
var utils = {
format: () => "A"
};
// Библиотека B (тоже использует utils)
var utils = {
format: () => "B" // перезаписал библиотеку A!
};
console.log(utils.format()); // "B" - библиотека A сломалась
4.2 Загрязнение пространства имён
javascript
// 100 глобальных переменных
var user = {};
var config = {};
var cache = {};
var helpers = {};
var api = {};
// ... и так далее
// Каждая из них может быть случайно перезаписана
4.3 Трудно отлаживать
javascript
function processData() {
// Забыли объявить переменную
result = calculate(); // случайная глобальная переменная
return result;
}
processData();
console.log(window.result); // "значение" - откуда оно взялось?
4.4 Проблемы с переименованием
javascript
// В одном файле
var pageTitle = "Главная";
// В другом файле (через 1000 строк)
var pageTitle = "О нас"; // перезаписал!
// Теперь везде "О нас"
Часть 5. Как избежать загрязнения глобального объекта
5.1 Используйте модули (ES6)
javascript
// math.js
export const PI = 3.14159;
export function add(a, b) { return a + b; }
// app.js
import { PI, add } from './math.js';
// Ничего не попало в глобальный объект
5.2 Используйте IIFE (старый способ)
javascript
(function() {
// Всё, что здесь, не попадает в глобальный объект
let privateVar = 42;
function privateFunc() {}
// Явно экспортируем только нужное
window.myModule = {
publicMethod: function() {}
};
})();
console.log(privateVar); // ReferenceError (не доступно)
5.3 Используйте одну глобальную переменную (неймспейс)
javascript
// Вместо 10 глобальных переменных - одна
const APP = {};
APP.user = { name: "Анна" };
APP.config = { theme: "dark" };
APP.utils = { formatDate() {} };
APP.api = { fetchUsers() {} };
// Риск конфликта минимален
5.4 Используйте let и const вместо var
javascript
// Не попадают в window (но всё ещё глобальны)
let globalLet = 42;
const GLOBAL_CONST = 100;
console.log(window.globalLet); // undefined
console.log(window.GLOBAL_CONST); // undefined
Часть 6. Полезные свойства глобального объекта
6.1 Проверка существования глобальных объектов
javascript
// Безопасная проверка перед использованием
if (typeof window !== "undefined") {
// Браузерный код
}
if (typeof global !== "undefined") {
// Node.js код
}
// Универсально
if (typeof globalThis.fetch === "function") {
// Поддерживается fetch
}
6.2 Полифиллы через глобальный объект
javascript
// Добавляем метод, если его нет
if (!globalThis.String.prototype.capitalize) {
globalThis.String.prototype.capitalize = function() {
return this.charAt(0).toUpperCase() + this.slice(1);
};
}
console.log("hello".capitalize()); // "Hello"
6.3 Глобальные флаги и конфигурация
javascript
// Для переключения режимов
globalThis.DEBUG = true;
function log(message) {
if (globalThis.DEBUG) {
console.log(`[DEBUG] ${message}`);
}
}
Часть 7. Реальные кейсы
7.1 Определение окружения
javascript
const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
const isNode = typeof global !== "undefined" && !isBrowser;
const isWorker = typeof self !== "undefined" && typeof importScripts === "function";
if (isBrowser) {
console.log("В браузере");
} else if (isNode) {
console.log("В Node.js");
} else if (isWorker) {
console.log("В Web Worker");
}
7.2 Глобальное состояние (осторожно!)
javascript
// Счётчик запросов для всего приложения
globalThis.requestCount = 0;
async function apiCall(url) {
globalThis.requestCount++;
const response = await fetch(url);
console.log(`Всего запросов: ${globalThis.requestCount}`);
return response;
}
7.3 Singleton через глобальный объект
javascript
// Гарантируем единственный экземпляр
if (!globalThis.appInstance) {
class App {
constructor() {
this.started = Date.now();
}
getUptime() {
return (Date.now() - this.started) / 1000;
}
}
globalThis.appInstance = new App();
}
const app = globalThis.appInstance;
Часть 8. Подводные камни
Камень #1: var в глобальной области создаёт неперечисляемое свойство
javascript
var x = 10;
console.log(Object.getOwnPropertyDescriptor(window, 'x'));
// { value: 10, writable: true, enumerable: false, configurable: false }
// Не перечисляется в for...in
for (let key in window) {
// x не появится
}
Камень #2: let и const не создают свойства window
javascript
let y = 20;
console.log(window.y); // undefined
// Но доступ к ним всё равно глобальный
console.log(y); // 20
Камень #3: Имя name уже занято
javascript
// В браузере window.name уже существует
console.log(window.name); // "" (пустая строка)
var name = "Анна"; // перезаписали!
console.log(window.name); // "Анна" - могли сломать что-то
Камень #4: globalThis не работает в очень старых браузерах
javascript
// Полифилл для globalThis
if (typeof globalThis === "undefined") {
(function() {
if (typeof window !== "undefined") {
window.globalThis = window;
} else if (typeof global !== "undefined") {
global.globalThis = global;
} else if (typeof self !== "undefined") {
self.globalThis = self;
} else {
this.globalThis = this;
}
})();
}
Часть 9. Альтернативы глобальным переменным
Итог: Манифест глобального объекта
- Глобальный объект есть всегда - в браузере window, в Node.js global, везде globalThis.
- var и function - создают свойства глобального объекта.
- let и const - не создают свойства, но всё ещё глобальны.
- Избегайте глобальных переменных - они ведут к конфликтам и багам.
- Используйте модули - современный способ изоляции кода.
- Одна глобальная переменная - лучше, чем много (но всё равно не идеально).
- globalThis - универсальный способ доступа к глобальному объекту.
Финальный тест (что выведет в браузере?):
javascript
var a = 1;
let b = 2;
const c = 3;
console.log(window.a);
console.log(window.b);
console.log(window.c);
window.d = 4;
console.log(d);
function test() {
x = 5;
}
test();
console.log(window.x);
Ответы: 1, undefined, undefined, 4, 5 (x стал глобальным из-за пропущенного var).
Глобальный объект - это мощный, но опасный инструмент. Он нужен для встроенных функций и иногда для глобальной конфигурации. Но в обычном коде глобальные переменные - это источник проблем. Используйте модули, локальные переменные и замыкания. Пусть ваш глобальный объект остаётся чистым, а код - предсказуемым. И помните: с великой силой приходит великая ответственность.