Является ли окно действительно глобальным в Javascript?

Возьмите этот кусок Javascript в браузере:

<script>

console.log(window.someThing);
var x = 12;

function foo() {
   window.otherThing = x;
}

</script>

Внутри foo мы можем получить доступ к window, мы все это знаем, но почему именно?

  • Это какая-то специальная глобальная переменная?
  • Или «корневая область» (внутри тега script) имеет его как неявную локальную переменную, и она просто «унаследована от замыкания», как может быть любая другая локальная переменная (например, x выше)?

И как это согласуется с тем, что переменные, объявленные непосредственно внутри тега script, устанавливаются как свойства window? (Или это не так?)

<script>
var x = 12;
function() {
   console.log(window.x);
}
</script>

person Bart van Heukelom    schedule 13.07.2011    source источник
comment
Ни одно из упомянутых окон не является глобальным объектом, все глобальные переменные являются свойствами окна. Это контейнер глобальных объектов. (Включая себя window.window)   -  person Raynos    schedule 14.07.2011
comment
@Raynos window.window   -  person KyleMit    schedule 20.01.2019


Ответы (7)


Причина, по которой вы можете получить доступ к переменным "вне области действия" или "бесплатно" в ECMAscript, заключается в так называемой цепочке области действия. Цепочка областей действия — это особое свойство каждого контекста выполнения. Как упоминалось несколько раз ранее, объект контекста выглядит примерно так:

  • [[объем]]
  • Переменная / объект активации
  • "это" значение контекста

каждый раз, когда вы обращаетесь к переменной (имя) в контексте (например, функции), процесс поиска всегда начинается в своем собственном Activation Object. Все формальные параметры, объявления функций и локально определенные переменные (var) хранятся в этом специальном объекте. Если имя переменной не было найдено в этом объекте, поиск переходит в цепочку [[Scope]]. Каждый раз, когда функция (-контекст) инициализируется, она копирует все переменные родительского контекста/объекты активации в свое внутреннее свойство [[Scope]]. Это то, что мы называем лексической областью действия. Вот почему Замыкания работают в ECMAscript. Поскольку Global context также имеет Variable Object (точнее, **переменный объект для глобального объекта является самим глобальным объектом), он также копируется в свойство functions [[Scope]].

Вот почему вы можете получить доступ к window из любой функции :-)

Приведенное выше объяснение имеет один важный концептуальный вывод: любая функция в ECMAscript является замыканием, что верно. Поскольку каждая функция будет как минимум копировать глобальный контекст VO в свое свойство [[Scope]].

person jAndy    schedule 13.07.2011
comment
Есть ли способ изменить цепочку областей действия? Например. чтобы функция не имела доступа к глобальной области видимости? - person pseudosavant; 13.06.2013
comment
Как синтаксически получить доступ к свойству [[Scope]]? - person overexchange; 07.09.2017

Является ли окно действительно глобальным в Javascript?

да. Если вы не создадите новую переменную с именем window в более узкой области

function foo() {
    var window;
}

Внутри foo мы можем получить доступ к окну, мы все это знаем, но почему именно?

Любая функция может обращаться к переменным, объявленным в более широкой области. В окне нет ничего особенного.

person Quentin    schedule 13.07.2011
comment
Но является ли область, в которой живет окно, просто самой широкой областью в цепочке областей или это специальная глобальная область? Как это разрешается внутренне во время выполнения движком Javascript? - person Bart van Heukelom; 13.07.2011
comment
Как я уже сказал, ничего особенного (ну, это не совсем так, поскольку это переменная по умолчанию, но в любом случае ничего особенного в отношении области видимости). - person Quentin; 13.07.2011
comment
@Bart van Heukelom: он проверит, есть ли в локальной области переменная с таким же именем, и если она не будет найдена, она будет идти вверх до Object. - person Shef; 13.07.2011
comment
@Shef До Объекта? Конечно, окно не является статическим свойством объекта... или нет? - person Bart van Heukelom; 13.07.2011
comment
@Bart van Heukelom: Извините, хотел написать Window объект. - person Shef; 13.07.2011

Все это определено в ECMAScript.

Глобальное — это лексическое окружение, не имеющее внешнего лексического окружения. Все остальные среды вложены в него и привязаны к глобальному объекту со свойствами, указанными в спецификации.

Это помещает свойства глобального объекта в начало цепочки областей действия, от которой наследуются все остальные среды.

ES 10.2.3 Глобальная среда:

Глобальная среда — это уникальная лексическая среда, которая создается до выполнения любого кода ECMAScript. Запись среды глобальной среды — это запись среды объекта, объектом привязки которой является глобальный объект (15.1). Ссылка на внешнюю среду глобальной среды имеет значение null.

По мере выполнения кода ECMAScript к глобальному объекту могут быть добавлены дополнительные свойства, а исходные свойства могут быть изменены.

ES 15.1. Глобальный объект

Уникальный глобальный объект создается до того, как элемент управления входит в какой-либо контекст выполнения.

Если не указано иное, стандартные встроенные свойства глобального объекта имеют атрибуты {[[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}.

Глобальный объект не имеет внутреннего свойства [[Construct]]. невозможно использовать глобальный объект в качестве конструктора с оператором new.

Глобальный объект не имеет внутреннего свойства [[Call]]; невозможно вызвать глобальный объект как функцию.

Значения внутренних свойств [[Prototype]] и [[Class]] глобального объекта зависят от реализации.

В дополнение к свойствам, определенным в этой спецификации, глобальный объект может иметь дополнительные свойства, определяемые хостом. Сюда может входить свойство, значением которого является сам глобальный объект; например, в объектной модели HTML-документа свойство окна глобального объекта является самим глобальным объектом.

person user113716    schedule 13.07.2011
comment
Если подумать, window.window.window.window.window === window.window.window.window. - person katspaugh; 13.07.2011
comment
Когда компилятор знает, когда остановиться, чтобы у нас не было бесконечного window.window.window и т. д.? - person Shaz; 27.07.2011
comment
@Shaz: Это циклическая ссылка, поэтому она не заканчивается. Компилятор создает только одну ссылку. Это просто ссылка на исходный объект, на котором была создана ссылка. Вот почему вы можете сделать window.window.window... вот так: var obj = {}; obj.obj = obj;. Создана только одна ссылка, но это ссылка на оригинал, так что вы можете сделать obj.obj.obj.obj.obj.obj.obj === obj. - person user113716; 27.07.2011

Это связано с цепочкой областей видимости.

Взгляните на следующую презентацию Николаса С. Закаса. (начиная с мин. 5)

person Saxoier    schedule 13.07.2011
comment
Интересно. Похоже, глобальная область видимости действительно обычная, только на самом высоком уровне. - person Bart van Heukelom; 13.07.2011

окно является базовой областью действия всех объектов javascript, и оно автоматически «присоединяется» к каждой переменной, которую вы определяете, если только вы не используете «var» перед объявлением, в этом случае область действия переменной является локальной (это означает, что она содержится внутри родительская функция или глобальная функция, если вы объявляете свою переменную вне функционального блока). Более того, окно определяется как константа, то есть вы не можете переопределить объект окна (вы получите сообщение об ошибке "ошибка типа: повторное объявление константного окна").

so:

window.foo = 5;

это то же самое, что:

var foo = 5;

or:

function() {
foo = 5;
}

но:

function() {
var foo = 5;
}

в этом случае "foo" является локальным (window.foo === undefined)

person daveoncode    schedule 13.07.2011
comment
Вы можете переопределить window. (function (window) { alert(window) })(1). - person katspaugh; 13.07.2011
comment
вы не переопределяете окно таким образом, вы создаете закрытие с аргументом с именем окна... это другое дело! :) - person daveoncode; 13.07.2011
comment
Синтаксис function неверен, требуется имя. переменная foo=2 в function f(){} не эквивалентна window.foo - person overexchange; 07.09.2017

Глобальная область window применяется только к основному потоку. В веб-воркерах нет глобальной переменной window. Вместо этого у вас есть WorkerGlobalScope внутри WebWorker и в SharedWorkerGlobalScope внутри SharedWorker.

Эта рабочая глобальная область хранится в переменной с именем self и, как описывает ее MDN:

эта область содержит информацию, обычно передаваемую объектами Window.

Это может стать проблемой, когда сторонний код, который вы используете в своем веб-воркере, использует объект окна. Это можно легко решить, объявив переменную window, как это было предложено @FelipeMicaroniLalli в его ответе здесь следующим образом:

var window = self;
person Wilt    schedule 02.06.2016

Насколько я понимаю, в книге Javascript: The Good Parts Дуглас Крокфорд объясняет, что window является глобальным объектом веб-браузер, содержащий все глобальные переменные. Это как Кольцо Всевластия...

person Vithozor    schedule 13.07.2011