![]() |
|
Модераторы: Sardar, Aliance |
![]()
|
|
| Zeroglif |
|
||||||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 644 Регистрация: 22.9.2005 Репутация: 28 Всего: 66 |
Коротко фиг обзовёшь. Вот, например, как совсем не коротко, но зато метко описывается это дело у Харольда Абельсона и Джеральда Джея Сассмана (Структура и интерпретация компьютерных программ):
В том же русле, но уже на базе родного ECMAScript сжато я бы сказал так:
Если совсем закоротить для удобства:
Ещё короче не горазд. Это сообщение отредактировал(а) Zeroglif - 24.11.2006, 12:24 |
||||||||
|
|||||||||
| SelenIT |
|
|||
![]() баг форума ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3996 Регистрация: 17.10.2006 Где: Pale Blue Dot Репутация: 49 Всего: 401 |
AKS, Zeroglif, спасибо! Zeroglif, Ваше второе определение вообще блеск, лучше для понимания, наверное, сформулировать просто невозможно. ++
-------------------- Осторожно! Данный юзер и его посты содержат ДГМО! Противопоказано лицам с предрасположенностью к зонеризму! |
|||
|
||||
| 12345c |
|
|||
![]() Круглый ![]() ![]() ![]() ![]() Профиль Группа: Vingrad developer Сообщений: 2018 Регистрация: 26.12.2005 Где: наша не пропадала ? Репутация: 57 Всего: 101 |
А исходное понятие closure лучше перевести (точнее, переназвать) как связывание или функция со связанными переменными.
Или ещё полнее, функция со связанными временными переменными (которые закончили своё существование). (При этом, если такого связывания нет, логичнее называть function функцией, как все делают, а не озадачивать народ глобальным утверждением, что в JS все функции - closures.) |
|||
|
||||
| Zeroglif |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 644 Регистрация: 22.9.2005 Репутация: 28 Всего: 66 |
Наоборот. Если все переменные в функции (binding form) связаны (bound), то откуда тогда взяться замыканию. A вот ежели переменные не связаны своей функцией (free), то налицо оно самое, то есть, как минимум, функция должна быть со свободными переменными (опустим для простоты причуды с возможной eval-изацией строки в переменную)...
Имхо умирают и заново рождаются только локальные bindings, а те, что ищутся в лексическом окружении, они как бы создаются единожды в момент создания функции (будущего замыкания). Я про имена, не про значения. Чтобы всё-таки вычленить замыкание из ряда остальных функций, что определённо имеет смысл, я бы сказал, что это функция, которая: 1) пережила контекст исполнения, в котором она была создана; 2) имеет на борту свободные переменные; Два основных лейбла. Под переменными подразумевается понятно что. Это сообщение отредактировал(а) Zeroglif - 26.2.2007, 03:25 |
|||
|
||||
| 12345c |
|
|||
![]() Круглый ![]() ![]() ![]() ![]() Профиль Группа: Vingrad developer Сообщений: 2018 Регистрация: 26.12.2005 Где: наша не пропадала ? Репутация: 57 Всего: 101 |
Я имел в виду связывание с константой или значением, оставшимся после закрытия переменной. Т.е., в терминах "free", это возможно как раз с free vars. Которые можно описать как определённые вне функции, но временные, не глобальные. Не параметры своей функции и не создавшиеся в ней.
Что считать free variables - локальные и глобальные или только локальные? Как я понимаю, свойства closure проявляются только с локальными free. Тогда, если термин "связывание" занят под противоположным действием - связыванием с переменными, то как назвать связывание с константой после закрытия (удаления) переменной? |
|||
|
||||
| AKS |
|
|||
|
Участник форума ![]() ![]() Профиль Группа: Участник Сообщений: 725 Регистрация: 20.9.2006 Репутация: 27 Всего: 52 |
А может быть под термином closure нужно понимать совсем другое "явление природы"?
Может быть замыкание - это факт существования Activation/Variable объекта outer-функции в св-ве [[Scope]] inner-функции? А момент, когда на объект inner-функции не останется ссылок и Activation/Variable объект outer-функции станет доступным для удаления из памяти, можно назвать "концом жизни" замыкания. |
|||
|
||||
| Zeroglif |
|
||||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 644 Регистрация: 22.9.2005 Репутация: 28 Всего: 66 |
Понимаешь, в этом смысле что глобальные, что "временные" технически суть одно и то же, если смотреть на них из-под замыкания, которое видит только строгую цепочку объектов в [[Scope]].
Свободные переменные - это те, что не связаны функцией, сюда же попадают и те, что будут связаны глобальным объектом. Но с другой стороны, тогда нет т.н целостности объекта (замыкания), т.к. есть доступ извне, не знаю, правда, насколько это принципиально.
В том и дело, что переменная (имя) не удаляется, если живёт замыкание, то живёт и [[Scope]], живут и все свободные переменные (имена). Технически (не углубляясь в специфику) переменную связывает определённый Variable Object, который создаётся один раз и не умирает, т.к. он сильно нужен замыканию, ибо оно может обращаться к свободным переменным, пытаясь найти связь в одном из Variable Objects. p.s. вышеописанное - есть смесь чуждых и не чуждых javascript терминов Добавлено @ 13:12 Именно так, я уже писал раньше в этой ветке, что функциональная терминология немного притянута за уши (ну, и бог с ней). Важен не только факт существования Activation/Variable объектов, важна и множественность такого существования под каждое замыкание... |
||||||
|
|||||||
| 12345c |
|
||||
![]() Круглый ![]() ![]() ![]() ![]() Профиль Группа: Vingrad developer Сообщений: 2018 Регистрация: 26.12.2005 Где: наша не пропадала ? Репутация: 57 Всего: 101 |
Добавлено @ 13:50 Да, но глобальные переменные не вызывают ощущения "чудес", если читатель кодов не знает про особенности функций в JS. Стоит глобальная переменная и стоит, оставаясь такой. Интуитивно предполагается, что глобальная не должна становиться значением в момент определения функции, а локальная должна, потому что известно, что она прекратит существование. Создатели поступили наоборот: живут все как переменные, более того, временные продолжают жить. Ну зомби натуральные. |
||||
|
|||||
| Sardar |
|
|||
![]() Бегун ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 6986 Регистрация: 19.4.2002 Где: Нидерланды, Groni ngen Репутация: 78 Всего: 317 |
Самое интересное, что легко узнать ещё на момент трансляции все переменные, используемые внутри closure. Отсюда действительно можно сделать "оптимизацию", физически разделив представление closure (функция связанная с лексическим контекстом) и функции (свободная функция).
12345c, в примере ты создал функции в переменных f2 и f3, не объявленных ранее, что привело к их автоматическому созданию в "самом верхнем контексте" a.k.a global. Это не очень хороший приём, т.к. засоряет global пространство имён. Добавлено @ 14:01 Знакомые с любым декларативным и"полу-декларативным" языком сразу всё поймут
Лучше всего понять это разделив переменную на значение и ссылку на значение. Объявляя переменную мы объявляем ссылку, присваивая значение мы изменяем ссылку на новое значение. Когда объект значение не имеет более ни одной ссылки, то он удаляется сборщиком мусора. Closure держит ссылки на все используемые значения, потому последние из памяти не удаляются, до тех пор, пока хоть кто нибудь ссылается на сам closure. Кстати, раз много-поточности в JS нет, то сборщик мусора реализуется элементарным подсчётом ссылок при каждой операции присвоения. -------------------- Опыт - сын ошибок трудных © А. С. Пушкин Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik Оценить мои качества можно тут. |
|||
|
||||
| Sardar |
|
||||
![]() Бегун ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 6986 Регистрация: 19.4.2002 Где: Нидерланды, Groni ngen Репутация: 78 Всего: 317 |
Впрочем тут нужна поправка, в случае настоящего JS полностью отбросить ссылку на родительский контекст нельзя (тем самым освободив ссылки на все не используемые значения, а следовательно возможно освободив и сами значения). А всё потому что eval должен видеть все переменные, как и "обычный код":
В примере видим, что для cool необходим только а, а b необходима не явно (отследить транслятором нельзя). Если реализовать функции и контексты эффективно, то мы отбросим контекст test, тогда eval должен вывести NaN (автоматом созданная b в global будет undefined, последующая арифметика в NaN). Но бродилки "правильно" выполняют код, показывая что все родительские контексты реально сохраняются. Впрочем транслятор может быть на столько умён, что бы отслеживать появление eval и сохранять контексты тогда, когда это нужно. Но это не оправдывает излишней свободы eval, препятствующей эффективной по памяти реализации closure/функций. -------------------- Опыт - сын ошибок трудных © А. С. Пушкин Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik Оценить мои качества можно тут. |
||||
|
|||||
| 12345c |
|
||||||
![]() Круглый ![]() ![]() ![]() ![]() Профиль Группа: Vingrad developer Сообщений: 2018 Регистрация: 26.12.2005 Где: наша не пропадала ? Репутация: 57 Всего: 101 |
Этот пример ничего не показывает - до выхода из test перем. b сохраняется. Модифицируем:
Но весь сыр-бор не для этого, а чтобы проверить, как влияет eval на скорость операций. Допишем:
2 пары - потому что они имеют обыкновение останавливаться и спрашивать: работать ли дальше? Результаты говорят, что обе функции работают с одинаковой скоростью, наличие eval не усугубляет время выполнения (IE6, FF2). Опять же ,они не о многом говорят, если и происходит операция с памятью, то она может быть очень незаметной по времени. Как выявить различия? (Найти чёрную кошку в тёмной комнате.) Сделать конструктор временного массива вместо b? (Почти доказано, что в окружении он сохранится.) Устроить утечку памяти и измерять скорость её роста? Второе интересно. Если сделать функцию, отхватывающую по 1-10 К памяти на временные переменные, и создавать такие функции в цикле, то по скорости роста памяти можно сказать, образумливается когда-либо браузер с запоминанием окружения или нет, очищает ли он когда-либо память окружения. Это сообщение отредактировал(а) 12345c - 27.2.2007, 15:51 |
||||||
|
|||||||
| Sardar |
|
|||
![]() Бегун ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 6986 Регистрация: 19.4.2002 Где: Нидерланды, Groni ngen Репутация: 78 Всего: 317 |
Нет, пример был что бы показать не возможность "отброса лишнего" при трансляции кода в байткод. Именно потому, что в JS код уже не является константой, а может модифицироваться из-за eval (тело функции другое из-за eval). Следовательно транслятор не способен определить какие ресурсы использует функция до этапа выполнения (изыскания на эту тему в фунегоидных языках). Другими словами реализуя интерпретатор JS я не смогу реализовать сохранение контекстов эффективно (в примере контекст от test будет висеть в памяти, удерживая ещё и b, хотя это не всегда нужно). Это к тому, что из-за такой казалось бы малой фичи как полная видимость переменных в eval делает код JS сложно транслируемым в бинарник. Просто мысли, к реальным браузерам не имеет отношения. Твой тест всего лишь показывает, что транслятор бродилки ипосльзоуемой в тесте возможно не так умён, что бы выявить closure без eval (возможно он вообще AST дерево эвалюирует), хотя такая фишка не очень сложна в реализации P.S. все мои мысли по поводу реализации JS из-за прошедшей лабы, написал язык Forthy, где объекты и closure реализованы почти как в JS. Eval не реализовывал (возможен парсинг и выполнение в рантайме, но видимы будут только используемые статическим кодом переменные), естественно контексты вышли фиксированными по размеру с линковкой по ссылке на этапе трансляции - читай шустро как в C'ях -------------------- Опыт - сын ошибок трудных © А. С. Пушкин Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik Оценить мои качества можно тут. |
|||
|
||||
| 12345c |
|
|||
![]() Круглый ![]() ![]() ![]() ![]() Профиль Группа: Vingrad developer Сообщений: 2018 Регистрация: 26.12.2005 Где: наша не пропадала ? Репутация: 57 Всего: 101 |
Это понятно, что мысли - для желающих написать свой язык. А ты свой переделывал в Пай-код? Или делался с расчётом на возможность трансляции до машинного?
Трансляция с eval видится возможной в виде гибрида - известный код транслируется, а в случае eval остаётся окружение с интерпретатором. И привязка машинных объектов к окружению (представление данных будет другим, поэтому надо иметь процедуру чтения машинного представления данных в интерпретаторе и наоборот). Но, возвращаясь к коду в браузерах, не очень приятное "открытие", что сохраняется весь контекст временных переменных в closure. Осталось выяснить, без eval он также будет сохранять весь контекст? |
|||
|
||||
| Sardar |
|
||||
![]() Бегун ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 6986 Регистрация: 19.4.2002 Где: Нидерланды, Groni ngen Репутация: 78 Всего: 317 |
Да в байткод (p-код). Его можно развернуть до машинного, но по сути будет масса вызовов функций (или threaded код), опкоды высокоуровневы (стек ориентированны). На следующей лабе попробую реализовать интерпретатор с JIT'ом (за одно попробую регистр-ориентированный p-код, как в parrot)
А ничего совершенно не отличается, если только не применять через-чур агрессивные оптимизации, а их не просто реализовать. Контексты функций это фиксированные по размеру массивы (линковка по ссылке), объекты это хеш-таблицы (линковка в рантайме по имени), переменные это вероятней всего tagged ссылки и т.д. -------------------- Опыт - сын ошибок трудных © А. С. Пушкин Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik Оценить мои качества можно тут. |
||||
|
|||||
| 12345c |
|
||||||||
![]() Круглый ![]() ![]() ![]() ![]() Профиль Группа: Vingrad developer Сообщений: 2018 Регистрация: 26.12.2005 Где: наша не пропадала ? Репутация: 57 Всего: 101 |
Вношу коррективу: вначале я измерял время по последнему скрипту не совсем правильно - вызывал одну и ту же первую функцию с eval по недосмотру. Сейчас исправил код, уменьшил счётчик в 10 раз, чтобы не было остановов в FF, и вот что FF2 выдал:
"Самый быстрый в мире" Opera9.0 работает типично так:
Добавлено @ 16:18 (И при этом в предыдущем эксперименте показано, что b сохраняется в IE в любом случае.) |
||||||||
|
|||||||||
![]()
|
| Форум для вопросов, которые имеются в справочниках, но их поиск вызвал затруднения, или для разработчика требуется совет или просьба отыскать ошибку. Напоминаем: 1) чётко формулируйте вопрос, 2) приведите пример того, что уже сделано, 3) укажите явно, нужен работающий пример или подсказка о том, где найти информацию. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | JavaScript: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |