Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   хитросплетения Global,контекст,this,Reference (https://javascript.ru/forum/misc/3158-khitrospleteniya-global-kontekst-reference.html)

Zeroglif 12.04.2009 19:35

Цитата:

Сообщение от kefi
контекстом функции

Контекст исполнения (execution context) - некая абстракция, изолирующая одну часть исполняемого кода от других частей в зависимости от того, что это за код. Исполняемый код лексически делится на три части - Global code, Function code, Eval code, отсюда и три вида контекста исполнения, по которым бродит js-интерпретатор. Контексты формируют стек, запустили сам скрипт - вошли в глобальный контекст, запустили функцию - вошли в контекст этой функции, запустили вложенную функцию - вошли в контекст вложенной функции, вернули что-то из вложенной - вышли из контекста вложенной и вернулись в контекст внешней, вернули что-то из внешней - вышли из контекста внешней и вернулись в глобальный контекст, отработал сам скрипт - вышли из глобального контекста... В любой точке сущестует один единственный активный/работающий контекст исполнения.

Цитата:

Сообщение от kefi
объектом переменных

Если говорить об именах, то js - это мир свойств. Переменные, параметры и имена объявленных функций должны стать свойствами некого объекта. Специально для них создаё(ю)тся объект(ы).

Цитата:

Сообщение от kefi
[[scope]] функции

http://javascript.ru/forum/offtopic/....html#post6885

kefi 13.04.2009 00:19

2 Zeroglif >
мда, что-то мутно там.

Мог бы кто понятно объяснить эти [[scope]], VO, контекст и иже с ними (какие-то, оказывается, еще спец объекты бывают ... ) , какие из этих объектов когда создаются, что они содержат и какие из них свойствами каких являются :
- при доRUN-time'оых FD определениях функций ,
- при FE определениях функций ,
- при вызове функций ?

Dmitry A. Soshnikov 13.04.2009 12:11

Вообще, там достаточно информации было, но попробую ещё проще; по частям, чтобы "уварилось". Начнём с VO.

Variable object (Объект переменных, сокращённо VO) - это объект, служащий хранилищем для:

1. переменных (var);
2. деклараций функций (function declaration, FD);
3. формальных параметров функции;

Главной особенностью здесь является то, что VO наполняется при входе в контекст, т.е. до выполнения кода контекста. Причём, в случае var'ов и недостающих формальных параметров под "наполнением" подразумевается резервирование слотов в VO со значением undefined.

Пример:

function test(a, b) {
  var c = 10;
  function d() {}
  var e = function _e() {};
  (function x() {});
}

test(10); // вызов


Этапы вызова:

1. Вход в контекст:

VO = {  // упрощённо; в реале он "наследуется" от Объекта активации
  a: 10,
  b: undefined,
  c: undefined,
  d: <reference to functionBody>
  e: undefined
};


2. Исполнение контекста:

VO['c'] = 10;
VO['e'] = <reference to "_e" functionBody>;


Всё. Как видим, функция "x", являясь FE (function expression), а не FD, не попала в VO (поскольку, ничего не было сказано про воздействие FE на VO в пунктах выше). Если попробовать вызвать функцию "x" за пределами объявления - будет ReferenceError. С другой стороны, "_e" также является FE, но последующее присвоение её переменной "e" оставляет на неё ссылку через VO["e"].

Если здесь всё понятно, и есть желание дальше изучать, можно будет продолжить.

update:

Эм.. Оказывается, я уже в этой теме писал почти тоже самое.

kefi 13.04.2009 12:59

Цитата:

Сообщение от Dmitry A. Soshnikov
Если здесь всё понятно, и есть желание дальше изучать, можно будет продолжить.

Да, VO, вроде понятно, но возник еще объект активации AO...
а еще есть arguments, [[scope]] , etc ... Да, и еще бы понять, чьи они свойства - если функции , то в глобальном контексте если находимся - тогда чьи ?

Dmitry A. Soshnikov 13.04.2009 23:26

Цитата:

Сообщение от kefi
но возник еще объект активации AO...

Activation object (Объект активации, AO) касается только контекста исполнения типа "Функция".

Кстати, в предыдущем посте, говоря о VO, в большей мере имелся в виду VO функции.

AO создаётся при входе в контекст функции и инициализируется свойством arguments, значением которого является Arguments object (Объект аргументов, обозначим ArgO, чтобы не путать с AO):

AO = {
  arguments: <ArgO>
};


Далее, этот AO становится ничем иным как VO. Поэтому, говоря о VO в контексте типа "функция", можно использовать и терминологию AO, т.к. здесь VO === AO. Образно в предыдущем посте (чтобы не перегужать и не приплетать arguments) я назвал это "наследуется", физически же, это тот же самый объект.

Говоря о VO в глобальном контексте, - сам глобальный объект является VO (в браузере - window).

Цитата:

Сообщение от kefi
а еще есть arguments,

Arguments object (ссылка выше) - объект, находящийся в VO/AO функции; содержит свойства:

- callee - ссылка на выполняемую функцию;
- length - количество реально переданных параметров;
- свойства-индексы (числовые, приведённые к строке), значения которых есть формальные параметры функции (слева направо в списке параметров). Количество этих свойств-индексов == arguments.length. Значения свойств-индексов объекта arguments и присутствующие формальные параметры - взаимозаменяемы:

function a(x, y, z) {
  alert(arguments.length); // 2
  alert(arguments.callee === a); // true
  alert(x === arguments[0]); // true
  alert(x); // 10
  arguments[0] = 20;
  alert(x); // 20
  x = 30;
  alert(arguments[0]); // 30
}

a(10, 20);


Цитата:

Сообщение от kefi
Да, и еще бы понять, чьи они свойства - если функции , то в глобальном контексте если находимся - тогда чьи ?

Если код входит в контекст функции, то это свойства функции. Если мы находимся в глобальном коде, то сам глобальный объект - есть VO.

Если всё понятно, можно будет продолжить про [[Scope]].

kefi 14.04.2009 23:46

Я понял так , еще немного допридумал, чтобы было логичнее, проверьте что не так :

Variable object (Объект переменных, сокращённо VO) - это объект, служащий хранилищем для:

1. переменных (var);
2. деклараций функций (function declaration, FD);
3. формальных параметров функции;

Главной особенностью здесь является то, что VO наполняется при входе в контекст, т.е. до выполнения кода контекста. Причём, в случае var'ов и недостающих формальных параметров под "наполнением" подразумевается резервирование слотов в VO со значением undefined.

Для глобального контекста :
VO===Global (где Global - встроенный глобальный объект) нашпиговывается ДО run-time слотами, которые по мере работы программы могут менять свои значения, но не свое количество или имена !

Для функции :
Если не было входа управления в контекст функции, то не существует для нее никакого ни VO, ни AO.
Если управление вошло во внутренний контекст функции F , то ДО ее выполнения для этой функции создается свой VO', при этом выполняются след шаги :
arguments = [<0аргумент>,<1аргумент,...];
 arguments.callee=F;
 arguments.length=<КолвоАргументовФункции_F>;
  AO = {  arguments: arguments };
  F.VO=AO;

При выходе из контекста функции выполняется :
delete F.VO
Цитата:

Если всё понятно, можно будет продолжить про [[Scope]].
"Огласите весь список, пожалуйста."

Dmitry A. Soshnikov 15.04.2009 00:31

Цитата:

Сообщение от kefi
Для глобального контекста :
VO===Global (где Global - встроенный глобальный объект) нашпиговывается ДО run-time слотами, которые по мере работы программы могут менять свои значения, но не свое количество или имена !

До исполнения, если встречаются: var и FD. Всё остальное (например, a = 10 (без var), либо явно - window.a = 10) - создаётся в runtime'e (и слот и его значение). Поэтому, Global свободно может менять свои слоты и значения этих слотов в runtime'e.

Цитата:

Сообщение от kefi
Если не было входа управления в контекст функции, то не существует для нее никакого ни VO, ни AO.

Да, так. Однако, [[Scope]] в функции зашит изначально и навсегда, не важно, будет ли запущена функция или нет.

Цитата:

Сообщение от kefi
Если управление вошло во внутренний контекст функции F , то ДО ее выполнения для этой функции создается свой VO', при этом выполняются след шаги :

Да.

Цитата:

Сообщение от kefi
F.VO=AO;

Можно и так, для удобства (абстрактно) обозначить.

Цитата:

Сообщение от kefi
delete F.VO

Да, только, если не было замыкания, тогда F.VO сохранится в [[Scope]] внутренней функции (т.е. не будет удалён, пока на него есть ссылка).

Цитата:

Сообщение от kefi
"Огласите весь список, пожалуйста."

[[Scope]] - это иерархическая цепь Объектов переменных (VO), стоящих выше контекста функции; цепь записывается свойством в функцию при её создании.

Scope (Scope chain, Иерархия областей видимости (в данном переводе)) - это цепь Объектов переменных, в которой происходит поиск значений при разрешении имен идентификаторов. Данная цепь создаётся при выполнении функии, и состоит из VO(текущей функции) и [[Scope]] функции:

Scope = VO + [[Scope]].

Можно ещё раз здесь почитать.

Пример:

var a = 10;
function b() {
  var c = 20;
  function d() {
    var e = 30;
    alert(a + c + e);
  }
  d();
  return d;
}
b();


Имеем:

VO(Global):

VO(Global) === Global = {
  a: 10
  b: <reference to functionBody>
};


При создании "b", [[Scope]] "b":

[[Scope]](b) = [
  VO(Global)
];


VO(b):

VO(b) = {
  c: 20,
  d: <reference to functionBody>
};


При запуске "b", Scope(b) = VO(b) + [[Scope]](b):

Scope(b) = [
  VO(b),
  VO(Global)
];


При создании внутрененней функции "d", [[Scope]] "d":

[[Scope]](d) = [
  VO(b),
  VO(Global)
];


VO(d):

VO(d) = {
  e: 30
};


При запуске "d", Scope(d) = VO(d) + [[Scope]](d):

Scope(b) = [
  VO(d),
  VO(b),
  VO(Global)
];


Разрешение имён идентификаторов "a", "c" и "e" при alert'e:

- "a"
-- VO(d) - не найдено;
-- VO(b) - не найдено;
-- VO(Global) - найдено - 10.


- "с"
-- VO(d) - не найдено;
-- VO(b) - найдено - 20.


- "е"
-- VO(d) - найдено - 30;


Т.е. Scope опрашивается по цепи вверх, если идентификатор не найден в родном VO.

При return d; остаётся ссылка на [[Scope]](d), поэтому все VO в цепи, стоящие иерархически выше - остаются в памяти.

kefi 15.04.2009 01:33

2 Dmitry A. Soshnikov >

Все яснее и яснее, Я сам-то мучился с этими терминами, понимал для себя только , что есть внешний контекст для каждой функции и внутренний. И как это все Вы поняли из ECMA спецификации , ума не приложу ...

Кстати контекст, как я сейчас понимаю, не является термином обозначающим некий объект, это чисто лексический контекст для текста функции или какого-ни слова из кода программы ?

Вот правда, еще остается непонятной роль AO - вроде как и нни к чему он , да еще какой-то непонятныйц остается спец объект из Вашей ссылки выше.

Цитата:

При return d; остаётся ссылка на [[Scope]](d), поэтому все VO в цепи, стоящие иерархически выше - остаются в памяти
Хотел уточнить :
- именно на [[Scope]] , т.е. БЕЗ VO функции d ?
- и сохраняются не просто , если возвращается return, как в Вашем примере b() , а если возвращаемое где-то сохранено var q=b() ?

Dmitry A. Soshnikov 15.04.2009 21:43

Цитата:

Сообщение от kefi
И как это все Вы поняли из ECMA спецификации , ума не приложу ...

Несомненно, стоит отметить этого человека - изначально, он помог мне поднять некоторые глубокие аспекты ("Этот человек", только ни в коем случае не считай это за лесть =) я просто благодарен и отдаю должное ;)). Углубляясь, изучая, дальше сам уже стандарт проштудировал (что и всем советую для профессионального понимания JavaScript).

Цитата:

Сообщение от kefi
Кстати контекст, как я сейчас понимаю, не является термином обозначающим некий объект, это чисто лексический контекст для текста функции или какого-ни слова из кода программы ?

Да, это абстракное определение, зависящее от типа кода: Global code, Eval code, Function code.

Цитата:

Сообщение от kefi
Вот правда, еще остается непонятной роль AO - вроде как и нни к чему он

AO - это и есть VO. А VO, в свою очередь, можно тоже считать абстракцией. Физически же, эта абстракция представлена AO (для функции и eval'a) и Global - для Global'a. У Global'a нет arguments, поэтому для функции это назвали AO. Если говорить отстраннённо от JS, можно представить VO - как интерфейс, а AO и Global - как конкретные классы, реализующие этот интерфейс.

Цитата:

Сообщение от kefi
да еще какой-то непонятныйц остается спец объект

Спец.объект - "анонимный объект", который содержит одно единственное свойство - опциональное имя FE, чтобы FE могла обратиться к себе рекрсивно по имени (помимо arguments.callee):

(function fn() {alert(fn);})();


Откуда alert(fn) выдаёт правильное значение, если FE не воздействуют на VO? Идентификатор fn не должен был попасть в VO(Global). Где же FE его находит? Специально для этого перед созданием FE создаётся этот спец. объект и кладётся в scope chain (в данном случае Global):

Scope(Global).{}.fn = <reference to FE "fn">


Дальше, когда создалась FE "fn", этот спец. объект удаляется из Scope(Global) - теперь он есть в [[Scope]](fn) и, соотвественно, может быть найден.

Здесь ещё можно почитать.

Цитата:

Сообщение от kefi
- именно на [[Scope]] , т.е. БЕЗ VO функции d ?

update: VO и Scope создаются каждый раз при вызове функции; запоминается только [[Scope]](d).

Цитата:

Сообщение от kefi
- и сохраняются не просто , если возвращается return, как в Вашем примере b() , а если возвращаемое где-то сохранено var q=b()

Да, конечно, это тоже подразумевалось.

kefi 15.04.2009 23:52

Цитата:

Конечно же с VO.
Чьим VO? я-то имел ввиду, что VO(d) не сохраняется поскольку НЕ НУЖЕН , т.к. при очередном вызове через замыкание он создается заново .


Часовой пояс GMT +3, время: 13:18.