Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

Хранение данных в замыкании, прием программирования модуль на Javascript кратко

Лекция



Привет, сегодня поговорим про хранение данных в замыкании, обещаю рассказать все что знаю. Для того чтобы лучше понимать что такое хранение данных в замыкании, прием программирования модули на js , настоятельно рекомендую прочитать все из категории Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend).

Замыкания можно использовать сотнями способов. Иногда люди сами не замечают, что использовали замыкания — настолько это просто и естественно.

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

Данные для счетчика

В примере ниже makeCounter создает функцию, которая считает свои вызовы:

Хранение данных в замыкании, прием программирования модуль на Javascript

Хранение текущего числа вызовов осуществляется в переменной currentCount внешней функции.

При этом, так как каждый вызов makeCounter создает новый объект переменных, то все создаваемые функции-счетчики взаимно независимы.

Хранение данных в замыкании, прием программирования модуль на Javascript

Добавим счетчику аргумент, который, если передан, устанавливает значение:

Хранение данных в замыкании, прием программирования модуль на Javascript

Здесь для проверки первого аргумента использовано сравнение с undefined, так что вызовыcounter(undefined) и counter() сработают идентично, как будто аргументов нет.

Объект счетчика

Можно пойти дальше и возвратить полноценный объект с функциями управления счетчиком:

  • getNext() — получить следующее значение, то, что раньше делал вызов counter().
  • set(value) — поставить значение.
  • reset() — обнулить счетчик.

Хранение данных в замыкании, прием программирования модуль на Javascript

…Теперь counter — объект с методами, которые при работе используют currentCount. Снаружи никак иначе, кроме как через эти методы, к currentCount получить доступ нельзя, так как это локальная переменная.

Объект счетчика + функция

К сожалению, пропал короткий красивый вызов counter(), вместо него теперь counter.getNext(). Но он ведь был таким коротким и удобным… Так что давайте вернем его:

Хранение данных в замыкании, прием программирования модуль на Javascript

Красиво, не правда ли? Тот факт, что объект — функция, вовсе не мешает добавить к нему сколько угодно методов.

Прием проектирования «Модуль»

Прием программирования «модуль» имеет громадное количество вариаций.

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

Оформление кода в модуль предусматривает следующие шаги:

  1. Создается функция-обертка, которая выполняется «на месте»: Хранение данных в замыкании, прием программирования модуль на Javascript
  2. Внутрь этой функции пишутся локальные переменные и функции, которые пользователю модуля не нужны, но нужны самому модулю:

    Хранение данных в замыкании, прием программирования модуль на Javascript

    Они будут доступны только изнутри.

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

    Если функция одна — это можно сделать явным возвратом return:

    Хранение данных в замыкании, прием программирования модуль на Javascript
    …Если функций много — можно присвоить их напрямую в window:
    Хранение данных в замыкании, прием программирования модуль на Javascript

    Или, что еще лучше, вернуть объект с ними:

Хранение данных в замыкании, прием программирования модуль на Javascript

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

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

Можно придумать и много других вариаций такого подхода. В конце концов, «модуль» — это всего лишь функция-обертка для скрытия переменных.

Задачи на понимание замыканий

Важность: 4

Напишите функцию sum, которая работает так: sum(a)(b) = a+b.

Да, именно так, через двойные скобки (это не опечатка). Например:

sum(1)(2) = 3
sum(5)(-1) = 4

Решение

Чтобы вторые скобки в вызове работали - первые должны возвращать функцию.

Эта функция должна знать про a и уметь прибавлять a к b. Об этом говорит сайт https://intellect.icu . Вот так:

Хранение данных в замыкании, прием программирования модуль на Javascript

Важность: 5

  1. Создайте функцию filter(arr, func), которая получает массивarr и возвращает новый, в который входят только те элементыarr, для которых func возвращает true.
  2. Создайте набор «готовых фильтров»: inBetween(a,b) — «между a,b»,inArray([...]) — «в массиве [...]».
    Использование должно быть таким:
    • filter(arr, inBetween(3,6)) — выберет только числа от 3 до 6,
    • filter(arr, inArray([1,2,3])) — выберет только элементы, совпадающие с одним из значений массива.

Пример, как это должно работать:

Хранение данных в замыкании, прием программирования модуль на Javascript

Решение
Функция фильтрации

Хранение данных в замыкании, прием программирования модуль на Javascript

Фильтр inBetween

Хранение данных в замыкании, прием программирования модуль на Javascript

Фильтр inArray

Хранение данных в замыкании, прием программирования модуль на Javascript

Важность: 5

В некоторых языках программирования существует объект «строковый буфер», который аккумулирует внутри себя значения. Его функционал состоит из двух возможностей:

  1. Добавить значение в буфер.
  2. Получить текущее содержимое.

Задача — реализовать строковый буфер на функциях в JavaScript, со следующим синтаксисом:

  • Создание объекта: var buffer = makeBuffer();.
  • Вызов makeBuffer должен возвращать такую функцию buffer, которая при вызове buffer(value) добавляет значение в некоторое внутреннее хранилище, а при вызове без аргументов buffer() — возвращает его.

Вот пример работы:

Хранение данных в замыкании, прием программирования модуль на Javascript

Буфер должен преобразовывать все данные к строковому типу:

Хранение данных в замыкании, прием программирования модуль на Javascript

Решение не должно использовать глобальные переменные.

Решение

Текущее значение текста удобно хранить в замыкании, в локальной переменнойmakeBuffer:

Хранение данных в замыкании, прием программирования модуль на Javascript

Начальное значение text = '' — пустая строка. Поэтому операция text += pieceприбавляет piece к строке, автоматически преобразуя его к строковому типу, как и требовалось в условии.

Важность: 5

Добавьте буферу из решения задачи Функция - строковый буфер методbuffer.clear(), который будет очищать текущее содержимое буфера:

Хранение данных в замыкании, прием программирования модуль на Javascript

Решение

Хранение данных в замыкании, прием программирования модуль на Javascript

Важность: 5

  • Будет ли работать доступ к переменной name через замыкание в примере ниже?
  • Удалится ли переменная name из памяти при выполненииdelete donkey.sayHi? Если нет — можно ли к name как-то обратиться после удаления donkey.sayHi?
  • А если присвоить donkey.sayHi = donkey.yell = null — останется ли name в памяти?

Хранение данных в замыкании, прием программирования модуль на Javascript

Решение
  1. Да, будет работать, благодаря ссылке [[Scope]] на внешний объект переменных, которая будет присвоена функциям sayHi и yell при создании объекта.
  2. Нет, name не удалится из памяти, поскольку несмотря на то, что sayHi больше нет, есть еще функция yell, которая также ссылается на внешний объект переменных. Этот объект хранится целиком, вместе со всеми свойствами.

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

  3. Если и sayHi и yell удалить, тогда, так как больше внутренних функций не останется, удалится и объект переменных вместе с name.

Важность: 5

Следующий код создает массив функций-стрелков shooters. По замыслу, каждый стрелок должен выводить свой номер:

Хранение данных в замыкании, прием программирования модуль на Javascript

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

Решение
Что происходит в этом коде

Функция makeArmy делает следующее:

  1. Создает пустой массив shooter:
    var shooters = [];
  2. В цикле заполняет массив элементами через shooter.push.
    При этом каждый элемент массива — это функция, так что в итоге после цикла массив будет таким:
    Хранение данных в замыкании, прием программирования модуль на Javascript
    Этот массив возвращается из функции.
  3. Вызов army () — это получение элемента массива (им будет функция) на позиции 5, и тут же — ее запуск.
Почему ошибка

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

В функциях-стрелках shooter отсутствует переменная i. Когда такая функция вызывается, то i она берет из внешнего LexicalEnvironment

Каким будет значение i?

К моменту вызова army (), функция makeArmy уже закончила работу. Цикл завершился, последнее значение было i=10.

В результате все функции shooter получают одно и то же, последнее, значение i=10.

Попробуйте исправить проблему самостоятельно.

Исправление (3 варианта)

Есть несколько способов исправить ситуацию.

  1. Первый способ исправить код - это привязать значение непосредственно к функции-стрелку:

    Хранение данных в замыкании, прием программирования модуль на Javascript

    В этом случае каждая функция хранит в себе свой собственный номер.

    Кстати, обратите внимание на использование Named Function Expression, вот в этом участке:

    Хранение данных в замыкании, прием программирования модуль на Javascript

    Если убрать имя me и оставить обращение через shooter, то работать не будет:

    Хранение данных в замыкании, прием программирования модуль на Javascript

    Вызов alert(shooter.i) при вызове будет искать переменную shooter, а эта переменная меняет значение по ходу цикла, и к моменту вызову она равна последней функции, созданной в цикле.

    Если использовать Named Function Expression, то имя жестко привязывается к конкретной функции, и поэтому в коде выше me.i возвращает правильный i.

  2. Другое, более продвинутое решение —- использовать дополнительную функцию для того, чтобы «поймать» текущее значение i:

    Хранение данных в замыкании, прием программирования модуль на Javascript

    Посмотрим выделенный фрагмент более внимательно, чтобы понять, что происходит:

    Хранение данных в замыкании, прием программирования модуль на Javascript

    Функция shooter создана как результат вызова промежуточного функционального выражения function(x), которое объявляется — и тут же выполняется, получая x = i.

    Так как function(x) тут же завершается, то значение x больше не меняется. Оно и будет использовано в возвращаемой функции-стрелке.

    Для красоты можно изменить название переменной x на i, суть происходящего при этом не изменится:

    Хранение данных в замыкании, прием программирования модуль на Javascript

    Кстати, обратите внимание — скобки вокруг function(i) не нужны, можно и так:

    Хранение данных в замыкании, прием программирования модуль на Javascript

    Скобки добавлены в код для лучшей читаемости, чтобы человек, который просматривает его, не подумал, что var shooter = function, а понял что это вызов «на месте», и присваивается его результат.

  3. Еще один забавный способ - обернуть весь цикл во временную функцию:

    Хранение данных в замыкании, прием программирования модуль на Javascript

    Вызов (function(i) { ... }) обернут в скобки, чтобы интерпретатор понял, что это Function Expression.

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

К сожалению, в одной статье не просто дать все знания про хранение данных в замыкании. Но я - старался. Если ты проявишь интерес к раскрытию подробностей,я обязательно напишу продолжение! Надеюсь, что теперь ты понял что такое хранение данных в замыкании, прием программирования модули на js и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)

создано: 2014-10-07
обновлено: 2022-02-17
132546



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей



Комментарии


Оставить комментарий
Если у вас есть какое-либо предложение, идея, благодарность или комментарий, не стесняйтесь писать. Мы очень ценим отзывы и рады услышать ваше мнение.
To reply

Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)

Термины: Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)