Что такое практическое использование для закрытия в JavaScript? - программирование
Подтвердить что ты не робот

Что такое практическое использование для закрытия в JavaScript?

Я пытается мой труднее обернуть голову вокруг закрытия Java.

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

Где это было бы полезно для меня? Возможно, я еще не совсем обнял его. Большинство примеров которые я видел в Интернете, не содержат никакого реального кода мира, просто смутные примеры.

Может ли кто-нибудь показать мне реальное использование крышкой?

Является ли это, например?

var warnUser = function (msg) {
    var calledCount = 0;
    return function() {
       calledCount++;
       alert(msg + '\nYou have been warned ' + calledCount + ' times.');
    };
};

var warnForTamper = warnUser('You can not tamper with our HTML.');
warnForTamper();
warnForTamper();
4b9b3361

Ответ 1

Я использовал закрытие, чтобы делать такие вещи, как:

a = (function () {
    var privatefunction = function () {
        alert('hello');
    }

    return {
        publicfunction : function () {
            privatefunction();
        }
    }
})();

Как вы можете видеть там, a теперь является объектом с методом publicfunction (a.publicfunction()), который вызывает privatefunction, который существует только внутри замыкания. Вы можете НЕ вызвать privatefunction напрямую (т.е. a.privatefunction()), просто publicfunction().

Его минимальный пример, но, может быть, вы можете увидеть его использование? Мы использовали это для применения общедоступных/частных методов.

Ответ 2

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

<button onclick="updateClickCount()">click me</button>  

Теперь может быть много подходов, таких как:

1) Вы можете использовать глобальную переменную и функцию для увеличения счетчика:

var counter = 0;

function updateClickCount() {
    ++counter;
    // do something with counter
}

Но подводный камень в том, что любой скрипт на странице может изменить счетчик, не вызывая updateClickCount().


2) Теперь вы можете подумать об объявлении переменной внутри функции:

function updateClickCount() {
    var counter = 0;
    ++counter;
    // do something with counter
}

Но эй! Каждый раз, когда updateClickCount() функция updateClickCount(), счетчик снова устанавливается в 1.


3) Думаете о вложенных функциях?

Вложенные функции имеют доступ к области "над" ними.
В этом примере внутренняя функция updateClickCount() имеет доступ к переменной счетчика в родительской функции countWrapper()

function countWrapper() {
    var counter = 0;
    function updateClickCount() {
    ++counter;
    // do something with counter
    }
    updateClickCount();    
    return counter; 
}

Это могло бы решить дилемму счетчика, если бы вы могли обратиться к функции updateClickCount() извне, и вам также нужно найти способ выполнить counter = 0 только один раз, а не каждый раз.


4) Закрытие на помощь! (функция, вызывающая себя):

 var updateClickCount=(function(){
    var counter=0;

    return function(){
     ++counter;
     // do something with counter
    }
})();

Самопризывающая функция запускается только один раз. Он устанавливает counter на ноль (0) и возвращает выражение функции.

Таким образом updateClickCount становится функцией. "Замечательная" часть заключается в том, что он может получить доступ к счетчику в родительской области видимости.

Это называется закрытием JavaScript. Это позволяет функции иметь "частные" переменные.

counter защищен областью действия анонимной функции и может быть изменен только с помощью функции добавления!

Более живой пример на Закрытие:

<script>
        var updateClickCount=(function(){
    	var counter=0;
    
    	return function(){
    	++counter;
    	 document.getElementById("spnCount").innerHTML=counter;
    	}
      })();
    </script>

    <html>
	 <button onclick="updateClickCount()">click me</button>
	  <div> you've clicked 
		<span id="spnCount"> 0 </span> times!
	 </div>
    </html>

Ответ 3

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

  • Передача параметризованного поведения в алгоритм (классическое программирование более высокого порядка):

    function proximity_sort(arr, midpoint) {
        arr.sort(function(a, b) { a -= midpoint; b -= midpoint; return a*a - b*b; });
    }
    
  • Имитация объектно-ориентированного программирования:

    function counter() {
        var a = 0;
        return {
            inc: function() { ++a; },
            dec: function() { --a; },
            get: function() { return a; },
            reset: function() { a = 0; }
        }
    }
    
  • Реализация управления экзотическим потоком, например обработка событий jQuery и API AJAX.

Ответ 4

Да, это хороший пример полезного закрытия. Вызов warnUser создает в своей области переменную calledCount и возвращает анонимную функцию, которая хранится в переменной warnForTamper. Поскольку по-прежнему существует закрытие, использующее переменную calledCount, оно не удаляется при выходе функции, поэтому каждый вызов warnForTamper() увеличивает область видимости и предупреждает о значении.

Самая распространенная проблема, которую я вижу в StackOverflow, - это то, где кто-то хочет "задержать" использование переменной, которая увеличивается на каждый цикл, но поскольку переменная ограничена, каждая ссылка на переменную будет после окончания цикла, в результате чего конечное состояние переменной:

for (var i = 0; i < someVar.length; i++)
    window.setTimeout(function () { 
        alert("Value of i was "+i+" when this timer was set" )
    }, 10000);

Это приведет к тому, что каждое предупреждение покажет то же значение i, значение которого было увеличено до окончания цикла. Решение состоит в том, чтобы создать новое замыкание, отдельную область для переменной. Это можно сделать, используя мгновенно выполненную анонимную функцию, которая получает переменную и сохраняет ее состояние как аргумент:

for (var i = 0; i < someVar.length; i++)
    (function (i) {
        window.setTimeout(function () { 
            alert("Value of i was "+i+" when this timer was set" )
        }, 10000);
    })(i); 

Ответ 5

Я знаю, что мне очень поздно отвечать на этот вопрос, но это может помочь любому, кто все еще ищет ответ в 2018 году.

Закрытие Javascript можно использовать для реализации функций дросселя и дебюта в вашем приложении.

Дросселирование:

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

Код:

const throttle = (func, limit) => {
  let isThrottling
  return function() {
    const args = arguments
    const context = this
    if (!isThrottling) {
      func.apply(context, args)
      isThrottling = true
      setTimeout(() => isThrottling = false, limit)
    }
  }
}

Вызов:

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

Код:

const debounce = (func, delay) => {
  let debouncing
  return function() {
    const context = this
    const args = arguments
    clearTimeout(debouncing)
    debouncing = setTimeout(() => func.apply(context, args), delay)
  }
}

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

Надеюсь, это поможет кому-то.

Ответ 6

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

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

var dateUtil = {
  weekdayShort: (function() {
    var days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
    return function(x) {
      if ((x != parseInt(x)) || (x < 1) || (x > 7)) {
        throw new Error("invalid weekday number");
      }
      return days[x - 1];
    };
  }())
};

Обратите внимание, что массив days можно просто сохранить как свойство объекта dateUtil, но тогда он будет виден пользователям script, и они могут даже изменить его, если они захотят, даже не нуждаясь в вашем исходный код. Однако, поскольку он заключен в анонимную функцию, которая возвращает функцию поиска по дате, она доступна только для функции поиска, поэтому теперь она защищена от несанкционированного доступа.

Ответ 8

Другим распространенным применением закрытий является привязка this в методе к определенному объекту, позволяющая его вызывать в другом месте (например, обработчик события).

function bind(obj, method) {
    if (typeof method == 'string') {
        method = obj[method];
    }
    return function () {
        method.apply(obj, arguments);
    }
}
...
document.body.addEventListener('mousemove', bind(watcher, 'follow'), true);

Всякий раз, когда срабатывает событие mousemove, вызывается watcher.follow(evt).

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

foo_a = function (...) {A a B}
foo_b = function (...) {A b B}
foo_c = function (...) {A c B}

становится

fooer = function (x) {
    return function (...) {A x B}
}

где A и B - не синтаксические единицы, а строки исходного кода (не строковые литералы).

См. "Упорядочение моего javascript с помощью функции" для конкретного примера.

Ответ 9

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

Без закрытия (https://jsfiddle.net/lukeschlangen/pw61qrow/3/):

function greeting(firstName, lastName) {
  var message = "Hello " + firstName + " " + lastName + "!";
  console.log(message);
}

greeting("Billy", "Bob");
greeting("Billy", "Bob");
greeting("Billy", "Bob");
greeting("Luke", "Schlangen");
greeting("Luke", "Schlangen");
greeting("Luke", "Schlangen");

С закрытием (https://jsfiddle.net/lukeschlangen/Lb5cfve9/3/):

function greeting(firstName, lastName) {
  var message = "Hello " + firstName + " " + lastName + "!";

  return function() {
    console.log(message);
  }
}

var greetingBilly = greeting("Billy", "Bob");
var greetingLuke = greeting("Luke", "Schlangen");

greetingBilly();
greetingBilly();
greetingBilly();
greetingLuke();
greetingLuke();
greetingLuke();

Ответ 10

Если вам нравится концепция создания экземпляра класса в объектно-ориентированном смысле (т.е. для создания объекта этого класса), то вы близки к пониманию закрытия.

Подумайте об этом так: когда вы создаете экземпляр двух объектов Person, вы знаете, что переменная-член класса "Имя" не разделяется между экземплярами; каждый объект имеет свою "копию". Аналогично, когда вы создаете закрытие, свободная переменная ('calledCount' в вашем примере выше) привязана к "экземпляру" функции.

Я думаю, что ваш концептуальный скачок немного затруднен тем фактом, что каждая функция/замыкание, возвращаемая функцией warnUser (в стороне от того, что функция более высокого порядка) связывает "calledCount" с тем же начальным значением (0), тогда как часто при создании замыканий более полезно передавать разные инициализаторы в функцию более высокого порядка, подобно передаче различных значений конструктору класса.

Итак, предположим, что, когда "calledCount" достигает определенного значения, вы хотите завершить сеанс пользователя; вам могут потребоваться разные значения для этого в зависимости от того, поступает ли запрос из локальной сети или большого плохого интернета (да, это надуманный пример). Для этого вы можете передавать разные начальные значения для callCount в warnUser (т.е. -3 или 0?).

Частью проблемы с литературой является номенклатура, используемая для их описания ( "лексический охват", "свободные переменные" ). Не позволяйте этому обмануть вас, затворы более просты, чем кажется... prima facie; -)

Ответ 11

Использование закрытий:

Закрытие - одна из самых мощных функций JavaScript. JavaScript допускает вложение функций и предоставляет внутренней функции полный доступ ко всем переменным и функциям, определенным внутри внешней функции (и всем другим переменным и функциям, к которым имеет доступ внешняя функция). Однако внешняя функция не имеет доступа к переменным и функциям, определенным внутри внутренней функции. Это обеспечивает некоторую безопасность для переменных внутренней функции. Кроме того, поскольку внутренняя функция имеет доступ к области внешней функции, переменные и функции, определенные во внешней функции, будут жить дольше, чем сама внешняя функция, если внутренней функции удается выжить за пределами жизни внешней функции. Закрытие создается, когда внутренняя функция каким-то образом доступна для любой области вне внешней функции.

Пример:

<script>
var createPet = function(name) {
  var sex;

  return {
    setName: function(newName) {
      name = newName;
    },

    getName: function() {
      return name;
    },

    getSex: function() {
      return sex;
    },

    setSex: function(newSex) {
      if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
        sex = newSex;
      }
    }
  }
}

var pet = createPet("Vivie");
console.log(pet.getName());                  // Vivie

console.log(pet.setName("Oliver"));   
console.log(pet.setSex("male"));
console.log(pet.getSex());                   // male
console.log(pet.getName());                  // Oliver
</script>

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

Ответ 12

Мне нравится функция Mozilla factory пример.

function makeAdder(x) {

    return function(y) {
        return x + y;
    };
}

var addFive = makeAdder(5);

console.assert(addFive(2) === 7); 
console.assert(addFive(-5) === 0);

Ответ 13

В шаблоне модуля JavaScript используются блокировки. Его приятный образец позволяет вам иметь что-то похожее "публичный" и "private" vars.

var myNamespace = (function () {

  var myPrivateVar, myPrivateMethod;

  // A private counter variable
  myPrivateVar = 0;

  // A private function which logs any arguments
  myPrivateMethod = function( foo ) {
      console.log( foo );
  };

  return {

    // A public variable
    myPublicVar: "foo",

    // A public function utilizing privates
    myPublicFunction: function( bar ) {

      // Increment our private counter
      myPrivateVar++;

      // Call our private method using bar
      myPrivateMethod( bar );

    }
  };

})();

Ответ 14

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

Jsfiddle

//Counter clouser implemented function;
var CartCouter = function(){
	var counter = 0;
  function changeCounter(val){
  	counter += val
  }
  return {
  	increment: function(){
    	changeCounter(1);
    },
    decrement: function(){
    changeCounter(-1);
    },
    value: function(){
    return counter;
    }
  }
}

var cartCount = CartCouter();
function updateCart(){
	document.getElementById('cartcount').innerHTML = cartCount.value();
  }

var productlist = document.getElementsByClassName('item');
for(var i = 0; i< productlist.length; i++){
	productlist[i].addEventListener('click',function(){
  	if(this.className.indexOf('selected')<0){
    		this.className += " selected";
        cartCount.increment();
        updateCart();
    } else{
    	this.className = this.className.replace("selected", "");
      cartCount.decrement();
      updateCart();
    }
  })
}
.productslist{
  padding:10px;
}
ul li{
  display: inline-block;
  padding: 5px;
  border: 1px solid #ddd;
  text-align: center;
  width: 25%;
  cursor: pointer;
}
.selected{
  background-color: #7CFEF0;
  color: #333;
}
.cartdiv{
  position: relative;
  float:right;
  padding: 5px;
  box-sizing: border-box;
  border: 1px solid #f1f1f1;
}
<div>
<h3>
Practical Use of JavaScript Closure consept/private variable.
</h3>
<div class="cartdiv">
    <span id="cartcount">0</span>
</div>
<div class="productslist">
    <ul >
    <li class="item">Product 1</li>
     <li class="item">Product 2</li>
     <li class="item">Product 3</li>
    </ul>

</div>
</div>

Ответ 15

Я написал статью некоторое время назад о том, как закрытие может использоваться для упрощения кода обработки событий. Он сравнивает обработку событий ASP.NET с клиентским jQuery.

http://www.hackification.com/2009/02/20/closures-simplify-event-handling-code/

Ответ 16

Еще один отличный пример - это класс конвертера:

function converter(toUnit, factor, offset, input) {
     offset = offset || 0;
     return [((offset+input)*factor).toFixed(2), toUnit].join(" ");
}

var milesToKm = converter.curry('km',1.60936,undefined);
var poundsToKg = converter.curry('kg',0.45460,undefined);
var farenheitToCelsius = converter.curry('degrees C',0.5556, -32);

milesToKm(10);            // returns "16.09 km"
poundsToKg(2.5);          // returns "1.14 kg"
farenheitToCelsius(98);   // returns "36.67 degrees C"

ОБЪЯСНЕНИЕ:
Когда вы объявляете локальную переменную... эта переменная... имеет область видимости. Смысл, он живет в "лексическом" объеме, в котором он объявлен.

Теперь...

Обратите внимание на переменную OFFSET - она ​​имеет собственную область. Теперь обратите внимание на RETURN, он также имеет свою собственную область действия, которая является областью возвращена и полностью отделена от области OFFSETS. И все же... как-то... значение OFFSET по-прежнему доступно для возвращаемой области (для использования).

Как?

Это то, что делает ЗАКРЫТИЕ: оно закрывает исходную область и инкапсулирует ее (например, конверт). Когда вы видите функцию, которая возвращает отдельную функцию (или отдельный результат, который не объявлен в исходной области), создается отдельная область... и... такая область видимости ЗАКРЫВАЕТСЯ в исходной области.

Следовательно, замыкание. Получите это?

Ответ 17

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

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

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Closures on button presses</title>
<script type="text/javascript">

window.addEventListener("load" , function () {
    /*
    grab the function from the first closure,
    and assign to a temporary variable 
    this will set the totalButtonCount variable
    that is used to count the total of all button clicks

    */
    var buttonHandler = buttonsCount(); 

    /*
    using the result from the first closure (a function is returned) 
    assign and run the sub closure that carries the 
    individual variable for button count and assign to the click handlers 
    */
    document.getElementById("button1").addEventListener("click" , buttonHandler() );
    document.getElementById("button2").addEventListener("click" , buttonHandler() );
    document.getElementById("button3").addEventListener("click" , buttonHandler() );

    // Now that buttonHandler has served its purpose it can be deleted if needs be
    buttonHandler = null;
});



function buttonsCount() {
    /* 
        First closure level 
        - totalButtonCount acts as a sort of global counter to count any button presses
    */
    var totalButtonCount = 0;

    return  function () {
        //second closure level
        var myButtonCount = 0;

        return function (event) {
            //actual function that is called on the button click
            event.preventDefault();
            /*  
               increment the button counts.
               myButtonCount only exists in the scope that is 
               applied to each event handler, therefore acts 
               to count each button individually whereas because 
               of the first closure totalButtonCount exists at 
               the scope just outside, so maintains a sort 
               of static or global variable state 
            */

            totalButtonCount++;
            myButtonCount++;

            /* 
                do something with the values ... fairly pointless 
                but it shows that each button contributes to both 
                it own variable and the outer variable in the 
                first closure 
            */
            console.log("Total button clicks: "+totalButtonCount);
            console.log("This button count: "+myButtonCount);
        }
    }
}

</script>
</head>

<body>
    <a href="#" id="button1">Button 1</a>
    <a href="#" id="button2">Button 2</a>
    <a href="#" id="button3">Button 3</a>
</body>
</html>

Ответ 18

Закрытие - это полезный способ создания , последовательность по возрастанию по запросу:

    var foobar = function(i){var count = count || i; return function(){return ++count;}}

    baz = foobar(1);
    console.log("first call: " + baz()); //2
    console.log("second call: " + baz()); //3

Ответ 19

Ссылка: Практическое использование закрытий

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

Пример метода сортировки массивов, который принимает в качестве аргумента функцию sort-condition:

[1, 2, 3].sort(function (a, b) {
    ... // sort conditions
});

Отображение функционалов как метод отображения массивов, который отображает новый массив по условию функционального аргумента:

[1, 2, 3].map(function (element) {
   return element * 2;
}); // [2, 4, 6]

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

 someCollection.find(function (element) {
        return element.someProperty == 'searchCondition';
    });

Кроме того, мы можем отметить применение функционалов, как, например, метод forEach, который применяет функцию к массиву элементов:

[1, 2, 3].forEach(function (element) {
    if (element % 2 != 0) {
        alert(element);
    }
}); // 1, 3

Функция применяется к аргументам (к списку аргументов - в применении и к позиционным аргументам - при вызове):

(function () {
  alert([].join.call(arguments, ';')); // 1;2;3
}).apply(this, [1, 2, 3]);

Отложенные вызовы:

var a = 10;
    setTimeout(function () {
      alert(a); // 10, after one second
    }, 1000);

Функции обратного вызова:

var x = 10;
// only for example
xmlHttpRequestObject.onreadystatechange = function () {
  // callback, which will be called deferral ,
  // when data will be ready;
  // variable "x" here is available,
  // regardless that context in which,
  // it was created already finished
  alert(x); // 10
};

Создание инкапсулированной области с целью скрытия вспомогательных объектов:

var foo = {};
(function (object) {
  var x = 10;
  object.getX = function _getX() {
    return x;
  };
})(foo);
alert(foo.getX());// get closured "x" – 10

Ответ 20

Большая часть кода, который мы пишем в интерфейсе JavaScript, основана на событиях - мы определяем какое-то поведение, а затем присоединяем его к событию, которое запускается пользователем (например, щелчком или нажатием). Наш код обычно прикрепляется как обратный вызов: одна функция, которая выполняется в ответ на событие. size12, size14 и size16 теперь являются функциями, которые будут изменять размер текста тела до 12, 14 и 16 пикселей соответственно. Мы можем прикрепить их к кнопкам (в данном случае ссылкам) следующим образом:

function makeSizer(size) {
    return function() {
    document.body.style.fontSize = size + 'px';
    };
}

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;

Fiddle

Ответ 21

В данном примере значение закрытой переменной 'counter' защищено и может быть изменено только с использованием заданных функций (приращение, декремент). потому что он находится в закрытии,

var MyCounter= function (){
    var counter=0;
    return {
    	increment:function () {return counter += 1;},
        decrement:function () {return counter -= 1;},
        get:function () {return counter;}
    };
};

var x = MyCounter();
//or
var y = MyCounter();

alert(x.get());//0
alert(x.increment());//1
alert(x.increment());//2

alert(y.increment());//1
alert(x.get());// x is still 2

Ответ 23

Очень хорошие ответы.

Стоит взглянуть на эти ссылки:

Документы MDN: закрытия

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

var makeCounter = function() {
   var privateCounter = 0;
   function changeBy(val) {
   privateCounter += val;
   }
return {
   increment: function() {
      changeBy(1);
   },
   decrement: function() {
     changeBy(-1);
   },
  value: function() {
     return privateCounter;
  }
}};

Другой случай использования в событиях:

function makeSizer(size) {
   return function() {
      document.body.style.fontSize = size + 'px';
   };
}
var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);

size12, size14 и size16 теперь являются функциями, которые изменят размер основного текста до 12, 14 и 16 пикселей соответственно.

Квора: Что такое "замыкание" в JavaScript?

Шаблон модуля:

var myModule = ( function(){
      var fname = "Phil";
      var lname = "Dunphy";
      var hobby = "Cracking Jokes and writing Phils-osophy";
      var work = function() {
         console.log( fname + "  " + lname + "is a Realtor and his hobby is " + hobby);
   } 
return { 
   "hobby" : hobby,
   "work" : work
   }
})();

myModule.fname; //  undefined
myModule.lname; //  undefined
myModule.hobby; // Cracking Jokes and writing Phils-osophy
myModule.work(); // Phil Dunphy  is a Realtor and his hobby is Cracking Jokes and writing Phils-osophy

Указывает на Примечание:

1- fname и lname являются частными для myModule и не доступны снаружи.

2- API определяется оператором return. Возвращенные вещи являются открытыми, остальные являются частными.

3- Вы можете переопределить myModule.work или myModule.hobby

4- Как fname (Phil) и lname (Dunphy) все еще печатаются при вызове myModule.work()? Разве они не должны быть приватными и недоступными после первого выполнения выражения myModule?

5- JavaScript создает замыкание (воспринимает его как границу) вокруг myModule. Теперь все, что возвращается функцией myModule, подвергается остальной части кода. Возвращенные объекты сохраняют контекст, в котором они были созданы.

6- Контекст означает все переменные и объект (включая функции), которые были доступны, когда выполнялось выражение функции.

7- Ссылка на fname и lname хранится в памяти до тех пор, пока в этом случае есть какая-либо ссылка на них через myModule.work.

Среда: практическое использование для замыканий

Функциональные фабрики

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

function dwightJob(title) {
    return function(prefix) {
       return prefix + ' ' + title;
   };
}

var sales = dwightJob('Salesman');
var manager = dwightJob('Manager');
alert(sales('Top'));  // Top Salesman
alert(manager('Assistant to the Regional')); // Assistant to the Regional Manager
alert(manager('Regional')); // Regional Manager

Пространство имен частных функций

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

var dwightSalary = (function() {
    var salary = 60000;
    function changeBy(amount) {
        salary += amount;
    }
    return {
        raise: function() {
            changeBy(5000);
        },
        lower: function() {
            changeBy(-5000);
        },
        currentAmount: function() {
            return salary;
        }
    }; 
})();

alert(dwightSalary.currentAmount()); // $60,000
dwightSalary.raise();
alert(dwightSalary.currentAmount()); // $65,000
dwightSalary.lower();
dwightSalary.lower();
alert(dwightSalary.currentAmount()); // $55,000
dwightSalary.changeBy(10000) // TypeError: undefined is not a function