Форум программистов, компьютерный форум, киберфорум
JavaScript для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.73/11: Рейтинг темы: голосов - 11, средняя оценка - 4.73
0 / 0 / 0
Регистрация: 22.02.2019
Сообщений: 207

Замыкание

29.07.2019, 12:35. Показов 2409. Ответов 25
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте. Не могу разобраться по теме замыкания.

Вот есть код
JavaScript
1
2
3
4
5
6
7
8
9
function makeCounter() {
  var currentCount = 1;
 
  return function() { // (**)
    return currentCount++;
  };
}
 
var counter = makeCounter(); // (*)
Вопрос вот в чем. Почему вызов функции присваивается именно в переменную? Почему нельзя просто вызвать ее так:
JavaScript
1
makeCounter()()
?
Она как бы работает, но если я повторно ее вызову, то значение не увеличивается, а остается таким же как и было.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
29.07.2019, 12:35
Ответы с готовыми решениями:

Замыкание
Есть вопрос по коду function makeArmy() { var shooters = ; for (var i = 0; i < 10;i++) { var shooter = function me() { ...

Замыкание
var a = 1; function b() { a = 10; return; function a() {} } b(); alert(a); Вот недавно читал статью про...

Замыкание
есть такой пример замыкания: function makeCounter() { var currentCount = 1; return function() { // (**) return...

25
Эксперт JS
6497 / 3908 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
29.07.2019, 12:48
Здравствуйте.
А здесь переменная на самом деле - ссылка на функцию.
PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
</head>
<body>
    <script>
        function makeCounter() {
            var currentCount = 1;
 
            return function () { // (**)
                return currentCount++;
            };
        }
 
        let func = makeCounter();
 
        console.log(func());
        console.log(func());
    </script>
</body>
</html>
Поэтому и постоянно повторяю - функция, которая возвращает функцию - это извращение в подавляющем большинстве случаев.
Этот паттерн крайне не эффективный и ненормально сложный для новичка.
0
0 / 0 / 0
Регистрация: 22.02.2019
Сообщений: 207
29.07.2019, 13:05  [ТС]
amr-now, А почему ссылка? Просто смотрю эти мануалы везде и все вызывают эту функцию с переменной, но не поясняют почему.

По какой причине я не могу вызвать эту функцию без переменной? Почему этот счетчик не работает?
0
Модератор
Эксперт HTML/CSS
 Аватар для AlexZaw
2381 / 1741 / 677
Регистрация: 07.08.2016
Сообщений: 4,095
29.07.2019, 13:08
Цитата Сообщение от Devero Посмотреть сообщение
то значение не увеличивается, а остается таким же как и было.
При каждом вызове функции без использования переменной вы каждый раз задаете значение currentCount = 1 заново, а при использовании переменной в ней хранится функция которая просто увеличивает currentCount. Т.е. при первом вызове с помощью counter возвращается 1 (которое было задано при первом вызове функции), и currentCount увеличивается на 1, при втором вызове вам возвращается уже увеличенное значение currentCount и оно опять увеличивается на 1 и т.д. При этом повторного переназначения currentCount уже не происходит, так как counter содержит в себе только внутреннюю функцию.
Как-то так.
Что-бы работал такой makeCounter()() вызов, вам нужно вынести currentCount в глобальную область видимости.
0
Эксперт JS
6497 / 3908 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
29.07.2019, 13:13
Цитата Сообщение от Devero Посмотреть сообщение
По какой причине я не могу вызвать эту функцию без переменной? Почему этот счетчик не работает?
Потому что на первых () создается экземпляр функции, на который никто и никогда в жизни ссылаться не будет.
Это природное явление в программировании называется "слабая ссылка".

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

Добавлено через 2 минуты
Чтобы два раза не вставать, реализуем то же самое в парадигме ООП:
PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
</head>
<body>
    <script>
        class Counter {
            constructor() {
                this.currentCount = 1;
            }
            get value() { return this.currentCount++; }
        }
 
        let counter = new Counter();
        console.log(counter.value);
        console.log(counter.value);
    </script>
</body>
</html>
0
0 / 0 / 0
Регистрация: 22.02.2019
Сообщений: 207
29.07.2019, 13:31  [ТС]
AlexZaw, Получается, если, как сказал
Цитата Сообщение от amr-now Посмотреть сообщение
А здесь переменная на самом деле - ссылка на функцию.
, то вызов этой переменной как бы перезаписывает функцию именно у себя, а не саму функцию и при последующем ее вызове она сохраненный результат в самой функции снова увеличивает? А если я просто вызову функцию без переменной, то я банально, как Вы и сказали, пытаюсь изменить currentCount = 1; (только что убедился в этом изменив постфиксный инкремент на префиксный). Правильно ли я понял?
0
Модератор
Эксперт HTML/CSS
 Аватар для AlexZaw
2381 / 1741 / 677
Регистрация: 07.08.2016
Сообщений: 4,095
29.07.2019, 13:54
Цитата Сообщение от Devero Посмотреть сообщение
Правильно ли я понял?
Все верно. После первого вызова с помощью counter() переменная counter хранит в себе ссылку на
JavaScript
1
2
3
function() {
    return currentCount++;
  };
и при последующих вызовах возвращает уже переменную через замыкание
1
0 / 0 / 0
Регистрация: 22.02.2019
Сообщений: 207
29.07.2019, 14:58  [ТС]
AlexZaw, Спасибо. Не могли бы Вы пояснить, почему мы ссылку передаем со скобками?
JavaScript
1
let func = makeCounter();
Ведь если мы хотим передать ссылку, то делаем это без них?
JavaScript
1
let func = makeCounter;
Я проверил, если я переменной задал именно функцию как ссылку, то работать переменная counter начинает так, как если бы я вызывал
JavaScript
1
makeCounter()()
0
Эксперт JS
6497 / 3908 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
29.07.2019, 15:24
Цитата Сообщение от Devero Посмотреть сообщение
почему мы ссылку передаем со скобками?
Потому что функция makeCounter() в конце своего выполнения возвращает экземпляр другой функции.
Вот здесь как раз происходит разрыв шаблона у новичков. Неоправданная сложность алгоритма.
---
Ссылка будет не на функцию makeCounter, а на новую анонимную функцию.

Добавлено через 4 минуты
Цитата Сообщение от Devero Посмотреть сообщение
то вызов этой переменной как бы перезаписывает функцию именно у себя
Формально и грамотно говоря, вызов makeCounter() создает новое окружение для замыкания. В это окружение входит новенькая анонимная функция со своей областью локальных переменных и внешняя переменная currentCount.

А поскольку окружение каждый раз при вызове makeCounter() создается заново, то currentCount в этот момент бесконечно будет становиться единицей.
0
0 / 0 / 0
Регистрация: 22.02.2019
Сообщений: 207
29.07.2019, 15:41  [ТС]
amr-now,
Цитата Сообщение от amr-now Посмотреть сообщение
Ссылка будет не на функцию makeCounter, а на новую анонимную функцию.
То есть ссылка будет идти на ту функцию, которая есть в функции makeCounter?

Цитата Сообщение от amr-now Посмотреть сообщение
Формально и грамотно говоря, вызов makeCounter() создает новое окружение для замыкания. В это окружение входит новенькая анонимная функция со своей областью локальных переменных и внешняя переменная currentCount.
А поскольку окружение каждый раз при вызове makeCounter() создается заново, то currentCount в этот момент бесконечно будет становиться единицей.
А если говорить не грамотно и для новичка? Как-то проще можно еще объяснить?
0
Эксперт JS
6497 / 3908 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
29.07.2019, 15:45
Devero, никак. Попейте кофе. Прочитайте еще раз эту переписку четыре раза.
Почитайте https://learn.javascript.ru/closures
и https://developer.mozilla.org/... t/Closures
1
0 / 0 / 0
Регистрация: 22.02.2019
Сообщений: 207
29.07.2019, 16:34  [ТС]
amr-now, Спасибо. Буду разбираться и вникать. Может быть у вас получится разъяснить еще о скобках, оборачивающих саму функцию?
JavaScript
1
2
3
4
5
6
(function() {
 
  alert( "объявляем локальные переменные, функции, работаем" );
  // ...
 
}());
0
Модератор
Эксперт HTML/CSS
 Аватар для AlexZaw
2381 / 1741 / 677
Регистрация: 07.08.2016
Сообщений: 4,095
29.07.2019, 17:07
Цитата Сообщение от Devero Посмотреть сообщение
Может быть у вас получится разъяснить еще о скобках, оборачивающих саму функцию?
Это анонимная самовызывающаяся функция. Вызывается сразу после своего объявления. Одна из целей IIFE - ограничить область видимости. Сделать так, чтобы переменные, объявленные в ней, не убежали в глобальную видимость.
0
0 / 0 / 0
Регистрация: 22.02.2019
Сообщений: 207
29.07.2019, 17:12  [ТС]
AlexZaw, Это я уже выяснил по литературе. Но сами скобки являются неким синтаксисом или можно по-другому еще это осуществить?
0
Модератор
Эксперт HTML/CSS
 Аватар для AlexZaw
2381 / 1741 / 677
Регистрация: 07.08.2016
Сообщений: 4,095
29.07.2019, 17:29
Devero, Можно еще так:
JavaScript
1
2
3
(function () {
    //body
})();
или так:
JavaScript
1
2
3
function () {
    //body
}();
0
Эксперт JS
6497 / 3908 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
29.07.2019, 17:48
Devero, сейчас мода вот так объявлять:
JavaScript
1
2
3
(async function main() {
  //body
})();
Это формальная точка входа в программу, понятная всем программистам языков, близких к Си.
В NodeJS так делать вообще типа круто. Программа сопли пузырями.
0
0 / 0 / 0
Регистрация: 22.02.2019
Сообщений: 207
29.07.2019, 17:53  [ТС]
AlexZaw, первый вариант точно такой же как я привел выше, а второй работать не будет, если исходить из того, что написано здесь - https://learn.javascript.ru/closures-module (не реклама).

Только вот не могу понять, что значит :

Дело в том, что «на месте» разрешено вызывать только Function Expression.

Общее правило таково:

Если браузер видит function в основном потоке кода – он считает, что это Function Declaration.
Если же function идёт в составе более сложного выражения, то он считает, что это Function Expression.
Что может значить "на месте" и "более сложное выражение"?
0
Модератор
Эксперт HTML/CSS
 Аватар для AlexZaw
2381 / 1741 / 677
Регистрация: 07.08.2016
Сообщений: 4,095
29.07.2019, 19:05
Цитата Сообщение от Devero Посмотреть сообщение
первый вариант точно такой же как я привел выше
Такой, да не такой, внимательно посмотрите на скобки.
Цитата Сообщение от Devero Посмотреть сообщение
Что может значить "на месте"
Значит что вызывается сразу же в момент ее объявления.
Цитата Сообщение от Devero Посмотреть сообщение
более сложное выражение"?
Function Expression, например, более сложное выражение, грубо говоря это если перед function есть еще какие-то операции.

Добавлено через 16 секунд
Цитата Сообщение от Devero Посмотреть сообщение
первый вариант точно такой же как я привел выше
Такой, да не такой, внимательно посмотрите на скобки.
Цитата Сообщение от Devero Посмотреть сообщение
Что может значить "на месте"
Значит что вызывается сразу же в момент ее объявления.
Цитата Сообщение от Devero Посмотреть сообщение
более сложное выражение"?
Function Expression, например, более сложное выражение, грубо говоря это если перед function есть еще какие-то операции.

Добавлено через 54 минуты
amr-now, а нормальное объяснение этому поведению есть? Кроме того что это модно
1
Эксперт JS
6497 / 3908 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
29.07.2019, 19:27
Цитата Сообщение от AlexZaw Посмотреть сообщение
а нормальное объяснение этому поведению есть? Кроме того что это модно
Что вам не нравится в поведении или объяснении?
У меня личное впечатление, что в данной теме уже сейчас содержится очень много полезных знаний.
0
Модератор
Эксперт HTML/CSS
 Аватар для AlexZaw
2381 / 1741 / 677
Регистрация: 07.08.2016
Сообщений: 4,095
29.07.2019, 19:33
Цитата Сообщение от amr-now Посмотреть сообщение
Что вам не нравится в поведении или объяснении?
Мне просто интересно есть ли какая-то практическая польза в такой форме записи и чем она отличается от такой:
JavaScript
1
2
3
(function () {
    //body
})();
кроме того что это модно и такая форма понятна для программистов C подобных языков (что в принципе веб-разработчиков вообще никак не должно волновать)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
29.07.2019, 19:33
Помогаю со студенческими работами здесь

Замыкание
Дорбый, Например у нас есть обычный счетчик функция var c1; var c2; var c3; function c() {

Не работает замыкание
Я новичок в JS , может чего не понял , но у меня не хочет работать замыкание: function testMegaFunc() { var topVar =...

Вложение.Замыкание
var summ = 0; function sumFun(arg) { summ += arg; console.log(summ); } sumFun(8); sumFun(10); sumFun(15); ...

Замыкание на addEvent
Здравствуйте, подскажите пожалуйста, как правильно выполнить замыкания для передачи конретного инстанса в метод? Есть подобный код: ...

Как работает замыкание
Когда использую 1 вариант цикла, то создается дополнительный индекс. Во 2 варианте все хорошо. Я не пойму момент с анонимной функцией,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
Отображение реквизитов в документе по условию и контроль их заполнения
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеСпецтехники", разработанного в конфигурации КА2. Данный документ берёт данные из другого нетипового документа. . .
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизитов табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: 1. Реализовать контроль заполнения реквизита. . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru