LINUX.ORG.RU

Неточности в определении замыкания в javascript

 , ,


0

1

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

Определение из mdn (на английском тоже самое)

Замыкание — это комбинация функции и лексического окружения, в котором эта функция была определена. Другими словами, замыкание даёт вам доступ к Scope (en-US) внешней функции из внутренней функции. В JavaScript замыкания создаются каждый раз при создании функции, во время её создания.

Два фрагмента кода

const fn = () => {
  let x = 5;
  if (true) {
    console.log(x); // Вот тут x не существует в текущем (if-овском) скоупе, переменная ищется (lookup?) в родительском (fn-овском) 
  }
}

Вопрос, откуда берется значение переменной x? Хочется сказать и думать что из замыкания, но замыкание работает с функциями, тут же блочный скоуп

Или вот например если у нас есть файл

let x = 6;
export const getX = () => x

в данном случае переменная x не находится в скоупе внешней функции, она находится в скоупе модуля

[UPD] Так по факту и не разобрались, но большинство склоняется к тому что второй пример является замыканием, а значит на mdn была неточность.

★★★

Последнее исправление: abs (всего исправлений: 3)
Ответ на: комментарий от alysnix

зачем вообще возвращать фактически незамкнутые лямбды, исполнение которых зависит от скрытого довеска неких данных

Это же классическое каррирование, создание функций которые получили промежуток нужных данных

const add = (x) => (y) => x+y
const add5 = add(5);
console.log(add5(10)); // 15;
console.log(add5(20)); // 25;
abs ★★★
() автор топика
Ответ на: комментарий от alysnix

В С++ нормальных замыканий нет. Есть подобие:

std::function<int()> make_my_closure(int x){
    return [x]() mutable {   
        ++x;
        return x;   
    };
}
Legioner ★★★★★
()

хочу создать видеоролик про замыкание и по этому хочу точно разобраться

а можно еще про монады?

cdshines ★★★★★
()

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

Например:

Every closure has three scopes:

Local Scope (Own scope)
Outer Functions Scope
Global Scope
cdshines ★★★★★
()
Ответ на: комментарий от abs

Это же классическое каррирование, создание функций которые получили промежуток нужных данных

в плюсах это делается через функторы, типа…

class MyFunctor{
  int _param;
public:
  MyFunctor(int fpar):_param(fpar){}
  int operator () (int fint) {return _param+fint; }
};

auto f1 = MyFunctor(100); /// 
auto f2 = MyFunctor(200);
int x = f1(10) + f2(10);

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

Ты так не делай. А то у меня смузи проилилось!

B0B
()
Ответ на: комментарий от alysnix

сего лишь слабое подобие нормального ооп,с красивыми классами и строгой типизацией.

Это уже далеко офтопик от моего вопроса, но что красивого в твоих 6 строках по сравнению с моей одной?

abs ★★★
() автор топика
Ответ на: комментарий от abs

Это уже далеко офтопик от моего вопроса, но что красивого в твоих 6 строках по сравнению с моей одной?

одна - это какая?

alysnix ★★★
()
Ответ на: комментарий от abs

внешней функции

Также там же «Замыкание — это комбинация функции и лексического окружения, в котором эта функция была определена.»

Также «Scope – The current context of execution».

Ты тупостью решил потроллить?

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Также «Scope – The current context of execution»

Не пугаем еду!

B0B
()
Ответ на: комментарий от no-such-file

Ты тупостью решил потроллить?

let x = 5
export const getX = () => x

Это является замыканием? Потому что это противоречит определению на MDN.

И от того что там дальше есть другое определение никак это противоречие не убирает

abs ★★★
() автор топика
Ответ на: комментарий от abs

Это является замыканием? Потому что это противоречит определению на MDN.

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от B0B

где оно берёт ‘x’?

Насколько я понимаю, поправляйте если не прав

Это общий принцип который не имеет отношения к замыканию. Когда мы в коде обращаемся к переменной она будет искаться в ближайшем(текущем) scope (который хранится в текущем environment record) если поиск будет неудачным то в ER хранится ссылка на внешний ER и алгоритм будет повторяться пока не найдется переменная или не дойдем до последнего ER)

abs ★★★
() автор топика
Ответ на: комментарий от alysnix

это в глобальном скопе написано?

В модуле (он же файл), модуль не является глобальным, и в другом файле эта переменная не будет доступна

abs ★★★
() автор топика
Ответ на: комментарий от abs

Это уже далеко офтопик от моего вопроса, но что красивого в твоих 6 строках по сравнению с моей одной?

если так грузит число строк, то можно написать темплейт функтора, и актуализировать его как надо, под разные «захваченные» типы и все такое… впрочем сие уже будет закосом в функциональщину, и это не наш путь.

alysnix ★★★
()
Ответ на: комментарий от abs

Это является замыканием?

Это не имеет значения, т.к поведение одинаковое будь это «глобальной» переменной модуля, или замыканием в getX.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

т.к поведение одинаковое будь это «глобальной» переменной модуля, или замыканием в getX

С этим я согласен

Это не имеет значения

Ну как не имеет значения? Я снимаю ролик про замыкания, и это важно является ли этой замыканием или нет. Я хочу четко для себя определить значение термина

abs ★★★
() автор топика
Ответ на: комментарий от anonymous

Оно РОЛИК ХОЧЕТ ЗАПИСАТЬ. Будет учить программированию, эксперт же.

Обычно книги пишут же …

anonymous
()
Ответ на: комментарий от abs

Я снимаю ролик про замыкания, и это важно является ли этой замыканием или нет.

Почему бы и нет?
Постарайтесь не растягивать его часа на два, как многие делают …

anonymous
()
Ответ на: комментарий от abs

Я снимаю ролик про замыкания, и это важно является ли этой замыканием или нет.

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

если это определение верно, то все, чему массивчик не требуется это уже не замыкание, а простая деревенская лямбда.

alysnix ★★★
()
Ответ на: комментарий от anonymous

Постарайтесь не растягивать его часа на два, как многие делают …

Думаю будет минут 10-20

abs ★★★
() автор топика
Ответ на: комментарий от alysnix

все, чему массивчик не требуется это уже не замыкание, а простая деревенская лямбда

Глобальный контекст не является чем-то особенным, т.о. «деревенская лямбда» это всего лишь вырожденный случай замыкания.

no-such-file ★★★★★
()
Ответ на: комментарий от abs

Потому что если поведение одинаково, то сущности эквивалентны. А раз они эквивалентны, то можно выбрать любое объяснение и оно будет верным. Иначе говоря оба объяснения верные.

no-such-file ★★★★★
()
Ответ на: комментарий от alysnix

а я модулы-2 и оберона-2 в машинный код

о, это объясняет твой затуп выше

EDIT: … и ниже.

Если можешь вернуть функцию, все ещё замкнутую на переменную, за пределы скоупа и при этом продолжить с этой же переменной работать по новому месту вызова — «замыкание». Не «ваше замыкание», а просто «замыкание».

А если функцию за пределы лексического скоупа не отдать, или отдать, но работать с той же переменной она не будет — «вложенные функции». Как в твоих паскакалях.

t184256 ★★★★★
()
Последнее исправление: t184256 (всего исправлений: 1)
Ответ на: комментарий от no-such-file

Потому что если поведение одинаково, то сущности эквивалентны.

Это же бред)

const x = 5;
export const getX = () => x

и

const x = 'Хлеб булочкин'
export const getX = () => 5

Поведение одинаково, но во втором случае замыканием и не пахнет, но пованивает 5 звездами на лоре, интересно почему?

abs ★★★
() автор топика
Ответ на: комментарий от t184256

Если можешь вернуть функцию, все ещё замкнутую на переменную, за пределы скоупа и при этом продолжить с этой же переменной работать по новому месту вызова — «замыкание». Не «ваше замыкание», а просто «замыкание».

тебе ж сказали - функторы, в ооп, они же классы со внутренним состоянием, и есть твои «замыкания». если тебя так уж парит по этому поводу.

опять же - вопрос изучи. не может никакое «замыкание» видеть переменную фрейма, который захлопнулся. может видеть ТОЛЬКО взятую копиюю… потому твое -

все ещё замкнутую на переменную, за пределы скоупа и при этом продолжить с этой же переменной работать по новому месту вызова

есть бред сивой кобылы.

alysnix ★★★
()

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

function blabla()
{
    var x = 5;
    this.getX=function()
    {
       return x;
    }
    this.incrX=function()
    {
        x++;
    }
}

Создаешь объект blabla. Доступ к переменной x доступен только из функций, благодаря замыканиям.

xmikex ★★★★
()
Ответ на: комментарий от alysnix

может видеть ТОЛЬКО взятую копиюю

Я не совсем понимаю о чем вы там выше спорите, но в JS там не копия, два замыкания могут использовать общею переменную.

abs ★★★
() автор топика
Ответ на: комментарий от xmikex

Замыкание это …

https://cs12.pikabu.ru/post_img/2021/09/01/11/1630521645156478933.png

Гайз, я знаю что такое замыкание, я пишу на JS лет 5. Я сейчас занимаюсь «буквоедством» (Чисто внешнее, буквальное понимание, формальное толкование чего-н. в ущерб смыслу, содержанию.)

Потому что я хочу создать подробный ролик про замыкание, очень подробный со всеми деталями. И то что я вижу в определении MDN противоречие меня расстраивает. Именно за разъяснением этого противоречия я и пришел

abs ★★★
() автор топика
Ответ на: комментарий от abs

Я не совсем понимаю о чем вы там выше спорите, но в JS там не копия, два замыкания могут использовать общею переменную.

при вызове функции создается фрейм ее локальных переменных. внутри есть типа замыкание которое «видит» локальную переменную в этом фрейме. замыкание выдается наружу функции и функция завершается. фрейм схлопывается. следующая функция уже занимает эту память своими локальными переменными.

а если выданное наружу ранее замыкание все еще видит локальные переменные старой функции… то простите - каким образом? в той памяти уже совершенно другие локальные переменные.

alysnix ★★★
()
Ответ на: комментарий от B0B

Оно его берёт при вызове функции, он спецом так накинул.

Так если это функция, то и должно брать. Какое значение есть на момент вызова функции в переменной x, то и вернётся. Классическое замыкание.

monk ★★★★★
()
Ответ на: комментарий от alysnix

и функция завершается. фрейм схлопывается.

Если язык поддерживает замыкания, то не схлопывается. В Си++ аналогом замыкания является объект. В нём же после окончания работы конструктора фрейм с полями объекта не схлопывается.

monk ★★★★★
()
Ответ на: комментарий от abs

напиши на js такую штуку

есть функция что выдает из себя замыкание, которое возвращает ее локальную переменную типа инт = 100.

вызови ее и получи это замыкание. присвой переменной типа инт результат вызова такого замыкания. будет это вообще компилироваться?

alysnix ★★★
()
Ответ на: комментарий от abs

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

xmikex ★★★★
()
Ответ на: комментарий от monk

Если язык поддерживает замыкания, то не схлопывается

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

alysnix ★★★
()
Ответ на: комментарий от abs

Поведение одинаково, но во втором случае замыканием и не пахнет

В первом тоже, нормальный компилятор заменит его на второй.

бред

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

no-such-file ★★★★★
()
Ответ на: комментарий от abs

определении MDN противоречие меня расстраивает

Если функция использует только глобальные переменные, то её замыканием не считают. Иначе придётся считать, что замыкания есть во всех языках, в которых есть глобальные переменные.

С точки зрения реализации тоже: замыкание должно быть двумя указателями (на код и на область с привязанными переменными). Если переменные глобальны, на них отдельного указателя не надо.

monk ★★★★★
()
Ответ на: комментарий от abs

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

xmikex ★★★★
()
Ответ на: комментарий от abs

Поведение одинаково, но во втором случае замыканием и не пахнет

С чего это одинаково?

x = 6
console.log(getX())

выдадут разное.

monk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.