Простой вызов функции — тот случай, когда её вызывают «голой»: без точки-владельца, без .call(), без new. Такой вызов не даёт движку никакой подсказки, каким должен быть this, и он подставляет значение по умолчанию — глобальный объект.
В браузере это window. В Node.js — global (или globalThis, работающий одинаково везде и добавленный в стандарт ES2020 именно для унификации). В Web Workers — self. В разных окружениях объект-корень называется по-разному, но идея одна: это тот верхний scope, куда попадают все глобальные переменные.
Базовый пример
// в браузере window — глобальный объект
function hello() {
// this — это window
console.log(this === window); // => true
}
hello();
Когда вызывается hello() без объекта-владельца, движок JavaScript автоматически подставляет глобальный объект как this. Это не отдельный «режим» — это просто default-поведение, к которому JavaScript прибегает, когда не знает лучше.
Проверим на более практичном примере:
function sum(a, b) {
console.log(this === window); // => true
this.result = a + b; // добавляем свойство глобальному объекту
return a + b;
}
sum(15, 16); // => 31
window.result; // => 31 (внутри функции создали глобальное свойство)
Внутри sum(), вызванной без объекта, this оказался равным window. Записать в this.result — значит записать в window.result. Такое поведение — главный источник «случайных глобальных» переменных в старом коде.
this вне функции — тоже глобальный объект
Когда this используется в глобальной области видимости (не внутри функции), он тоже указывает на глобальный объект:
console.log(this === window); // => true
this.myString = 'Привет, Мир!';
console.log(window.myString); // => 'Привет, Мир!'
Тот же эффект в html-файле, где скрипт исполняется на уровне документа:
<script type="text/javascript">
console.log(this === window); // => true
</script>
Но здесь есть важное исключение — ES-модули. В файле, подключённом как <script type="module">, this на верхнем уровне — undefined, не window. То же в TypeScript-модулях, в файлах Node с "type": "module":
// в обычном <script>:
console.log(this); // => window
// в <script type="module">:
console.log(this); // => undefined
Это разумно: модули изолированы, их «верхний уровень» больше похож на тело функции, чем на глобальный скоуп.
Ловушка: var vs let/const в глобальной области
Странная историческая деталь: переменные, объявленные через var в глобальной области, становятся свойствами window. А let и const — нет:
var oldStyle = 'hello';
let newStyle = 'world';
const anotherNew = '!';
console.log(window.oldStyle); // => 'hello' (var — попадает в window)
console.log(window.newStyle); // => undefined (let — не попадает)
console.log(window.anotherNew); // => undefined (const — тоже не попадает)
Это одна из причин, почему в современном коде мы пишем только let и const: глобальный объект остаётся чистым, никаких случайных «загрязнений» через объявление переменной.
Строгий режим меняет поведение
Правило про this = глобальный объект работает только в нестрогом режиме. В строгом режиме ('use strict') this при простом вызове — undefined. Разбор строгого режима — в следующей подглаве. Здесь — краткое напоминание, чтобы не удивляться, увидев undefined вместо window.
'use strict';
function hello() {
console.log(this); // => undefined
this.name = 'oops'; // TypeError: Cannot set properties of undefined
}
hello();
Все ES-модули работают в строгом режиме автоматически — 'use strict' писать не надо. То же самое для тел классов ES6 — они по умолчанию strict.
Когда это может быть полезно
В современном коде «this в простом вызове» редко используется целенаправленно — это скорее ловушка, о которой надо помнить. Но пара сценариев осмысленно опирается на это правило:
- Полифилы и legacy-код. Библиотеки, которые должны работать и в браузере, и в Node, часто используют (function() { ... }).call(this) в качестве обёртки, чтобы получить доступ к глобальному объекту в неизвестной среде.
- Global-объявления в старом стиле. До появления globalThis (ES2020) идиома var globalObject = (function() { return this; })() работала как способ получить «тот самый глобальный объект» в любой среде.
Основное правило современной практики: если ты пишешь this внутри функции, вызываемой «просто» (без объекта, без .call(), без new) — ты почти наверняка ошибаешься. Проверь, не должен ли это быть метод объекта, стрелочная функция или явная привязка через .bind().