Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   apply и call. В чём отличия? (https://javascript.ru/forum/offtopic/5156-apply-i-call-v-chjom-otlichiya.html)

Riim 21.09.2009 14:06

Цитата:

Сообщение от ZoNT
Если вопрос только в этом то надо было писать так:

замыкания опять же нет, вопрос был не в способе запомнить что-то в "new Function", а в том, что там в памяти, запомнен ли чей-то scope.

B~Vladi 21.09.2009 14:11

Цитата:

Сообщение от Riim
вопрос не в способе запомнить в что-то в "new Function", а в том что там в памяти, запомнен ли чей-то scope

Я подразумеваю, что второе - результат работы первого...Только вот этот самый результат не нужен...

Riim 21.09.2009 14:20

B~Vladi, можно через prototype, можно просто создавать нормальную структуру объектов, так что бы до всего нужного можно было добраться через window.

B~Vladi 21.09.2009 14:55

Ладно, не буду вас доставать:)

Dmitry A. Soshnikov 21.09.2009 15:45

Цитата:

Сообщение от Riim
замыкания опять же нет, вопрос был не в способе запомнить что-то в "new Function", а в том, что там в памяти, запомнен ли чей-то scope.

Цитата:

Сообщение от ZoNT
Функция через new Function ничего не запоминает

Вообще, каждая функция имеет [[Scope]], просто для функций, созданных с помощью конструктора Function, [[Scope]] содержит только глобальный объект.

А в виду того, что любая функция хранит [[Scope]] (т.е. Scope chain порождающего контекста), все функции являются замыканиями.

B~Vladi 21.09.2009 17:11

Цитата:

Сообщение от Dmitry A. Soshnikov
А в виду того, что любая функция хранит [[Scope]] (т.е. Scope chain порождающего контекста), все функции являются замыканиями.

Аха... Тогда ещё такой вопрос:
Есть код:

function fnc1(){
  var i;
  function fnc2(){
    alert(i)
  }
}


А внешний [[scope]], который хранит функция fnc2 - это клон или ссылка на [[scope]] функции fnc1?! Т.е. меня интересует как при этом расходуется память...

Dmitry A. Soshnikov 21.09.2009 17:23

Цитата:

Сообщение от B~Vladi
А внешний [[scope]], который хранит функция fnc2 - это клон или ссылка

Ссылка; там же, в статье о замыканиях можно подробно посмотреть.

Цитата:

Сообщение от B~Vladi
или ссылка на [[scope]] функции fnc1?!

Свойство [[Scope]] функции - это ссылка на Scope (Scope chain) порождающего (внешнего) контекста, а не на [[Scope]] внешней функции. Если бы была ссылка на [[Scope]] внешней функции, внутренняя функция не видела бы переменные, объявленные во внешней функции.

Т.е.

f1.[[Scope]] === Scope глобальньного контекста === [Global]


Scope (Scope chain) контекста функции f1 === Объект активации (AO) контекста функции f1 + f1.[[Scope]]:

Scope(f1 Context) == AO(f1 context) + f1.[[Scope]]


А f2.[[Scope]]:

f2.[[Scope]] === Scope(f1 Context) === [AO(f1 context), Global]

Riim 21.09.2009 17:42

Dmitry A. Soshnikov, вот такой у меня вопрос: функция запомнила какие-то переменные, если внутри этой функции создать переменную, одноименную с той, что запомнена, то она как бы экранируется, теперь если экранируется все запомненное за счет имен аргументов, то хранится ли в памяти внешняя функция? Что-то у меня не получается создать пример подтверждающий или опровергающий это. Вот код для пояснения вопроса:
var p = (function() {// func1
	var a = 5, b = 6;
	return function(a, b) {// смысла, хранить в памяти func1, вроде нет, все равно все экранировано, и убрать это экранирование вроде никак (delete применяется к свойствам объектов, но a и b непонятно чьи свойства)
		alert(a + b);
	};
})();

Dmitry A. Soshnikov 21.09.2009 18:07

Цитата:

Сообщение от Riim
если внутри этой функции создать переменную, одноименную с той, что запомнена, то она как бы экранируется

Да, "экранируется", на этом принципе и работает Scope chain.

Т.е. одноимённые переменные (а также, декларации функций и формальные параметры) более глубокого контекста, разрешаются (определяются) раньше, чем переменные с тем же именем, но в контексте выше. Цепь областей видимости контекста (Scope chain) при нахождении в коде переменной, опрашивается интерпретатором от самого глубого звена цепи вверх до глобального объекта (и, в некоторых реализациях, прототипа глобального объекта).

var a = 10;
function A() {
  var a = 20;
  function B() {
    var a = 30;
    alert(a); // найдено сразу в AO(контекста B)
  }
}


Если бы переменная "а" была объявлена один раз (глобально), то при alert(a) из внутренней функции "B", она бы разрешалась по цепи (Scope chain контекста функции "B"):

1. AO(контекста "B") - (нет) ->
2. AO(контекста "А") - (нет) ->
3. VO(Global) === Global - (да) - 10


Цитата:

Сообщение от Riim
теперь если экранируется все запомненное за счет имен аргументов, то хранится ли в памяти внешняя функция

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

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

function A() {
  var a = 10;
  function B() { // нужен ли этой функции Scope A?
    function C() {
      alert(a); // если B не запомнит Scope A, функция С не найдёт "а"
    }
  }
}


Но, повторю, по идее, может быть проведена оптимизация на уровне реализации.

Поэтому, все функцию при создании запоминаю лексический контекст (т.е. Scope chain этого контекста), в котором они порождены, отсюда - все функции - замыкания. Функция может быть ни разу не запущена, но [[Scope]] уже в неё записался.

Но, стандарт описывает предложение по оптимизации - объединённые объекты:

function a() {
  function b(z) {
    return z * z;
  }
  return b;
}
 
var x = a();
var y = a();


Т.к. [[Scope]] функций x и y - не различим (и вообще, оба объекты - не различимы), реализация вправе использовать объединённые объекты в этом случае, или даже - использовать один объект. Поэтому, не всегда внутренняя функция будет создаваться каждый раз разная.

Riim 21.09.2009 20:09

Цитата:

Сообщение от Dmitry A. Soshnikov
С другой стороны, одна вложенная функция может не иметь свободных переменных, а вложенная во вложенную может, поэтому, надо запоминать всегда

совсем обрубать цепочку, конечно, не стоит, она в любом случае должна закончиться на VO(Global) === Global , я имел в виду аккуратно удалять незначащие звенья в этой цепи, вот здесь, например:
function A() {
  var a = 10;
  function B() { // нужен ли этой функции Scope A?
    function C() {
      alert(a); // если B не запомнит Scope A, функция С не найдёт "а"
    }
  }
}

можно не запоминать AO(контекста "B") и из "C" сразу в "A" ссылаться.
Правда я уже не уверен, что такая оптимизация пойдет на пользу, памяти конечно меньше надо будет, но при каждом создании функции столько дополнительной работы делать, с другой стороны там и так этой работы очень много делается.


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