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)

kefi 31.03.2009 22:01

Цитата:

Сообщение от 2 Dmitry A. Soshnikov
1. FE создаётся в рантайме (тогда как FD создается до построчного выполнения скрипта);

Это Значит, что если в конструкторе есть такое выражение
this.action1=function(){ /* код функции */; },
то оно будет создавать новую функцию при каждом вызове этого конструктора для построения объекта ?
Если да, то тогда будет лучше для экономии памяти и времени делать
в конструкторе так :
function F (){ /* код функции */; },
this.action1=F ;
?

Dmitry A. Soshnikov 31.03.2009 23:05

kefi, нет. Всё-таки, слово "скрипт" получилось несколько путанным в этой формулировке (вот только недавно насчёт этого же вопрос был).

Перефразирую точнее:

FD создается при входе в контекст исполнения, до построчного его выполнения. Если контекст один - глобальный, то тут можно сказать и "весь скрипт".

Всего есть три контекста: глобальный, функция и eval (подробней - в ссылке ниже).

Поэтому, при входе в функцию её Variable object (Объект переменных, пункт 10.1.3) наполняется снова.

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

В первом случае, у Вас FE:

this.action1=function(){ /* код функции */; };


Такая функция, как было сказано, создаётся в рантайме и не воздействует на VO, однако, последующее присвоение её свойству this.action1 оставляет функцию в памяти (иначе FE можно выполнить только сразу при объявлении, т.к. в VO они не попадают и дальше вызвать их нельзя).

Во втором случае, у Вас FD:

function F (){ /* код функции */; }
this.action1=F ;


И, хотя, эта функция будет создана при входе в контекст исполнения (до выполнения кода функции), всё равно, функция будет так же создана новая - для каждого объекта своя.

Цитата:

Сообщение от kefi
Если да, то тогда будет лучше для экономии памяти

А вот для экономии памяти, общие свойства объектов (как правило, это методы), лучше вынести в прототип:

function A(state) {
  this.state = state; // у каждого объекта своё свойство
  this.fn = function () {}; // тоже своё
  function fn2() {}
  this.fn2 = fn; // тоже своё
}

// а вот методы - описаны единожды,
// но так же доступны всем порождённым
// объектам - за счёт делегации к прототипу
A.prototype = {
  constructor: A,
  test: function () {
    alert(this.a);
  }
};

// можно и отдельно описывать методы в прототипе
A.prototype.test2 = function () {
  alert(this.state + ' test2');
};

var a = new A(10);
var b = new A(20);

a.test(); // 10
b.test(); // 20

alert([
  a.hasOwnProperty('state'), // true
  b.hasOwnProperty('state'), // true

  a.hasOwnProperty('fn'), // true
  b.hasOwnProperty('fn'), // true

  a.hasOwnProperty('fn2'), // true
  b.hasOwnProperty('fn2'), // true

  a.hasOwnProperty('test'), // false, нет родного свойства, возьмётся из прототипа
  b.hasOwnProperty('test') // false, аналогично
]);


Ссылка: http://javascript.ru/ecma/part10#a-10. Особенно можно посмотреть пункт 10.1.3, именно там говорится, что (var'ы, FD, и формальные параметры) и когда (при входе в контекст исполнения) создаётся (попадает в Variable object функции).

Zeroglif 31.03.2009 23:35

Цитата:

Сообщение от kefi
в конструкторе так :
function F (){ /* код функции */; },
this.action1=F ;

Можно вынести F наружу из конструктора.

kefi 31.03.2009 23:48

Цитата:

Во втором случае, у Вас FD:
Код:

function F (){ /* код функции */; }
this.action1=F ;

И, хотя, эта функция будет создана при входе в контекст исполнения (до выполнения кода функции), всё равно, функция будет так же создана новая - для каждого объекта своя.
Ну я еще могу понять для первого случая с FE, логично: каждый создаваемый объект содержит одельную копию тела метода. Расход памяти , правда, большой.
Но! Как же так получается для второго случая с FD, функция определяется единожды - еще до run-time, но опять каждый объект содержит отдельную копию тела функции ?
Или все же не тела в обоих случаях, а ссылки на одно и тоже тело ?
В чем причина? В ECMA упорно не могу догнать, что написано.


PS
Цитата:

Можно вынести F наружу из конструктора.
Да, я понимаю это. Но не хочется из-за разрущения инкапсуляции.

Zeroglif 01.04.2009 00:00

Цитата:

Сообщение от kefi
еще до run-time

Функция - это свой маленький скриптик. Поэтому до рантайма этого скриптика. А так как вы вызываете каждый раз, то и создание каждый раз.

Dmitry A. Soshnikov 01.04.2009 00:11

Цитата:

Сообщение от kefi
Как же так получается для второго случая с FD, функция определяется единожды - еще до run-time

Нет, не единожды. Каждый раз при входе в контекст исполнения. Функция - это тоже контекст исполнения. Runtime здесь имеется в виду - выполнения кода контекста исполнения.

function fn () {
  var a = function _a() {};
  function b() {}
}


Что произошло:

1. Входим в контекст исполения функции "fn":

- Заполняется VO:

VO['a'] - создалась переменная "а", значение undefined;
VO['b'] - создалась FD "b";

2. Выполняем код контекста функции "fn" (вот он, runtime контекста):

- создалась FE "_a"
- VO['a'] = FE "_a"

Цитата:

Сообщение от kefi
Или все же не тела в обоих случаях, а ссылки на одно и тоже тело ?

Вообще, это вопрос о связывании переменных. Есть блок кода под определённым именем:

name ---> блок кода


Или:

function name() {
  // блок кода
}


Далее, присваиваем _name ссылку (тип Reference) на тот же блок кода:

var _name = name;

name ---> блок кода <--- _name

alert(name === _name); // true


Старое имя связываем с новым блоком кода:

name = function () {
  // новый блок кода
};

_name ---> блок кода
name ---> новый блок кода

alert(name === _name); // false


Восстанавливаем:

name = _name;


P.S.: а, отвлекался, долго писал, Zeroglif ответил уже.

kefi 01.04.2009 00:59

Цитата:

долго писал, Zeroglif ответил уже.
Спасибо, за усилия конечно, но все же :
Что же получается, что если в теле функции опредлены внутренние функции, то при каждом вызове этой функции ( входе в ее контекст )
будут создаваться и компилироваться новые копии тел вложеных функций ? Но зачем их создавать заново, и компилировать заново, если и после первого одного входа в контекст внешней функции уже интерпретатору должно быть понятно, что текстуально все нутро этой функции определено и меняться более оно текстуально не будет ?

Где же тогда рациональность спецификации ?

Zeroglif 01.04.2009 09:27

Цитата:

Сообщение от kefi
Где же тогда рациональность спецификации ?

Рациональность заключается в том, что объекты уникальны и функция не исключение. Если рассматривать совокупное значение (value) функции, как некое сочетание 'body+scope chain+object value', то в вашем конструкторе при одном и том же 'body' у вложенной функции разный 'scope chain' и разный 'object value' (иначе присваиваемые свойства у метода одного "экземпляра" отражались бы на методе другого).

С другой стороны стандарт предусматривает оптимизацию, разрешая 'joined objects', но я чего-то сейчас не вижу, чтобы этим кто-то пользовался. Внутренняя самодельная оптимизация наверняка существует, но нам это не важно, если это не противоречит установленной логике или не выпячивает разницу в скорости.

kefi 01.04.2009 09:50

2 Zeroglif > А ну так все же у вложенной функции для разных объектов разный 'scope chain' , но "при одном и том же 'body' " ?
Т.е. на каждом объекте замыкается только свой [[scope]], но текст тела для всех один общий ?

Zeroglif 01.04.2009 10:07

Даже не знаю, как объяснять. Ну, вот вы видите внутри конструктора некую функцию:

this.x = function(){...};

Представьте, что вместо функции там объект:

this.x = {};

Создавая "экземпляры", вы создаёте разные объекты 'this.x' иначе у каждого экземпляра был бы один и тот же. Та же самая история с функциями, которые те же объекты, только сложнее. У них разница усиливается необходимостью удерживать scope chain, которая (цепь) теоретически всегда разная, т.к. создаётся в момент вызова и "привязывается" к создаваемой функции в момент создания. К тому же у каждой функции при создании есть пара - прототип будущих экземпляров, это тоже уникальная черта каждого потенциального конструктора.


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