Для чего нужны JS-закрытия? [Дубликат]

Более новое решение может быть доступно в пакете purrr. Для вашего точного вопроса вы можете использовать reduce() отметить малый r по сравнению с base::Reduce, но вы могли бы полностью устранить проблему, используя map_dfr() или map_dfc, которые могли бы предотвратить проблему, сделав карту и уменьшить шаг в одном.

221
задан Ram 22 July 2015 в 17:33
поделиться

20 ответов

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

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

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

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

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

188
ответ дан chris Frisina 17 August 2018 в 15:17
поделиться
  • 1
    Ах, если это закрытие, то я использовал закрытие, не зная об этом! Я часто помещаю функции внутри другого, а затем выставляю все, что мне нужно, публично, возвращая литерал объекта, как в вашем примере. – alex 28 April 2010 в 11:44
  • 2
    Да, как вы видите, вы сохраняете контекст функции, потому что объект, который вы возвращаете, ссылается на переменные (и функции) внутри него. Таким образом, вы использовали их, вы просто не знали об этом. – Francisco Soto 28 April 2010 в 11:54
  • 3
    Технически каждая функция, которую вы создаете в Javascript в браузере, является закрытием, потому что объект окна привязан к нему. – Adam Gent 28 April 2010 в 13:17
  • 4
    Я знаю, что это старый вопрос, но для меня это все равно не дает адекватного ответа. Почему бы просто не вызвать функцию напрямую? Зачем вам нужна частная функция? – qodeninja 3 February 2014 в 21:17
  • 5
    Потому что, хотя пример имеет только функцию, он также может иметь переменные, которые not доступны извне. Скажем: var obj = (function () {var value = 0; return {get: function () {return value;}, set: function (val) {value = val;}}}) (); obj.set (20); obj.get (); = & GT; 20 и т.д. – Francisco Soto 5 February 2014 в 20:17

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

    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

Различия суммируются следующим образом:

Anonymous functions                                    Defined functions

Cannot be used as a method                             Can be used as a method of an object

Exists only in the scope in which it is defined        Exists within the object it is defined in

Can only be called in the scope in which it is defined Can be called at any point in the code

Can be reassigned a new value or deleted               Cannot be deleted or changed

Ссылки

0
ответ дан 4 revs 17 August 2018 в 15:17
поделиться

Здесь у меня есть один простой пример концепции закрытия, который мы можем использовать на нашем сайте электронной коммерции или многих других. Я добавляю ссылку 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>

0
ответ дан Abhilash 17 August 2018 в 15:17
поделиться

Да, это хороший пример полезного закрытия. Вызов 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); 
18
ответ дан Andy E 17 August 2018 в 15:17
поделиться
  • 1
    Интересно -1, я думаю, это не «практическое использование для закрытия в javascript»? – Andy E 28 April 2010 в 12:25
  • 2
    Я нашел некоторое использование при чтении, поэтому я наградил +1 перед нисходящим. – alex 28 April 2010 в 12:49
  • 3
    @alex: Спасибо, я заметил верхнюю часть. Я почти привык к анонимным downvotes здесь, в SO. Меня это только раздражает, потому что я действительно хотел бы знать, сказал ли я что-то неточное или неправильное, и они, как правило, заставляют вас думать, что вас только что уволили некоторые другие ответчики, которые хотят лучше видеть их собственный ответ. К счастью, я не мстительный тип ;-) – Andy E 28 April 2010 в 15:30
  • 4
    Я думаю, что это более эффективная работа для уязвимости JavaScripts. Вы должны просто добавить var j = i; перед первым setTimeout и получить предупреждение, чтобы использовать j. Другая работа вокруг - использовать «с» следующим образом: for (var i = 0; i & lt; someVar.length; i ++) {с ({i: i}) {window.setTimeout (function () {alert (& quot; Значение i было «+ i +», когда был установлен этот таймер »}}, 100);}} – davidbuttar 3 September 2013 в 18:17
  • 5
    @AndyE Funny может и не быть правильным словом. Я просто заметил, что часто люди используют функции самозапускания для объяснения закрытий, как и многие ответы на этой странице. Но функция обратного вызова в setTimeout также является закрытием; это можно рассматривать как «практическое применение». так как вы можете получить доступ к некоторым другим локальным переменным из обратного вызова. Когда я узнал о закрытии, осознав, что это было полезно для меня - это закрытие повсюду, а не только в аркадных шаблонах JavaScript. – antoine 16 July 2018 в 15:32

Другим распространенным применением закрытий является связывание 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 с помощью функции » для конкретного примера.

5
ответ дан Community 17 August 2018 в 15:17
поделиться
6
ответ дан Dan Dascalescu 17 August 2018 в 15:17
поделиться
  • 1
    Просматривая это, я не вижу, как это «практично». как будто я удаляю все return function ()..., код все еще работает нормально. Закрытие не является обязательным – an earwig 15 August 2015 в 02:47
  • 2
    @James_Parsons Затем вы не можете назначить их обработчикам событий, как это было сделано в примере. – alex 16 August 2015 в 23:57

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

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

<!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's 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>
0
ответ дан Darren Crabb 17 August 2018 в 15:17
поделиться

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

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

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

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

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

4
ответ дан EdwardGarson 17 August 2018 в 15:17
поделиться

Предположим, вы хотите подсчитать количество нажатий кнопки пользователя на веб-странице. Для этого вы вызываете функцию на 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(), счетчик снова устанавливается на 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. Это дает возможность для функции иметь переменные [ private .

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>
85
ответ дан JerryGoyal 17 August 2018 в 15:17
поделиться
  • 1
    Это первый ответ, который заставил меня сказать «О, , что , почему я буду использовать закрытие!». – Scott Beeson 7 June 2017 в 15:45
  • 2
    ты сделал мой день :) – JerryGoyal 7 June 2017 в 18:54
  • 3
    Я только что прочитал страницу w3schools на закрытии, а затем пришел сюда для получения дополнительной информации. Это то же самое, что и страница w3schools: w3schools.com/js/js_function_closures.asp – tyelford 14 June 2017 в 12:31
  • 4
    @JerryGoyal вы могли бы заставить его работать с двумя отдельными кнопками? Я не могу понять, как без использования двух переменных (копий функции), которые, похоже, устраняют некоторые из основных преимуществ / удобства. – Tyler Collier 14 September 2017 в 07:14
  • 5
    Хороший ответ. Обратите внимание, что для закрытия не требуется нужна функция самозапускания, но она может быть. Когда замыкание является самоисключением (т. Е. Сразу вызываемое добавлением () после функции), это означает, что возвращаемое значение немедленно вычисляется, а не возвращается function , и возвращаемое значение позже после вызова функции. Закрытием может быть любая функция внутри другой функции, а ее ключевой характеристикой является то, что она имеет доступ к области родительской функции, включая ее переменные и методы. – Chris Halcrow 13 February 2018 в 11:28

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

Без закрытия ( 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();
5
ответ дан Luke Schlangen 17 August 2018 в 15:17
поделиться

В языке 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, но тогда он будет виден пользователям сценария, и они могут даже изменить его, если они захотят, даже не нуждаясь в исходном коде. Однако, поскольку он заключен в анонимную функцию, которая возвращает функцию поиска по дате, она доступна только для функции поиска, поэтому теперь она защищена от несанкционированного доступа.

13
ответ дан maerics 17 August 2018 в 15:17
поделиться
  • 1
    Это может показаться глупым, но не могли ли они просто открыть сам файл JavaScript и увидеть вашу реализацию? – itsmichaelwang 15 December 2014 в 07:49
  • 2
    @ Zapurdead: да, они могли бы, конечно, видеть реализацию, но не могли изменить реализацию (случайно или намеренно) без прямого изменения исходного кода. Я полагаю, вы могли бы сравнить его с защищенными членами на Java. – maerics 15 December 2014 в 16:36

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

  1. Передача параметризованного поведения в алгоритм (классическое программирование более высокого порядка):
    function proximity_sort(arr, midpoint) {
        arr.sort(function(a, b) { a -= midpoint; b -= midpoint; return a*a - b*b; });
    }
    
  2. Моделирование объектно-ориентированного программирования:
    function counter() {
        var a = 0;
        return {
            inc: function() { ++a; },
            dec: function() { --a; },
            get: function() { return a; },
            reset: function() { a = 0; }
        }
    }
    
  3. Реализация управления экзотическим потоком, например, обработка событий jQuery и API AJAX.
61
ответ дан Marcelo Cantos 17 August 2018 в 15:17
поделиться
  • 1
    (int?) Последнее, что я проверил, JavaScript был утиным языком. Возможно, вы думали о Java? – Hello71 5 November 2010 в 02:41
  • 2
    @ Hello71: Я думал о JavaScript, но старые привычки умирают тяжело. Хороший улов. – Marcelo Cantos 5 November 2010 в 05:23
  • 3
    @MarceloCantos похоже, что вы забыли запятую в реализации счетчика. Я отредактировал ваш пост, чтобы исправить его. Надеюсь, что все в порядке :) – streppel 9 January 2014 в 18:08
  • 4
    @Streppel: Хорошая добыча! Я больше чем рад за то, что вы сделали мой код лучше. :-) – Marcelo Cantos 10 January 2014 в 11:58
  • 5
    пытаясь понять # 1 ... Как бы вы назвали proximity_sort? – Dave2081 11 December 2014 в 17:25

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

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

Пример метода сортировки массивов, который принимает в качестве аргумента функцию 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
};

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

var foo = {};
(function (object) {
  var x = 10;
  object.getX = function _getX() {
    return x;
  };
})(foo);
alert(foo.getX());// get closured "x" – 10
0
ответ дан Merlin 17 August 2018 в 15:17
поделиться

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

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

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

Дросселирование ограничивает максимальное число раз, когда функция может быть вызвана с течением времени. Как и в «выполнить эту функцию не чаще одного раза в 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)
    }
  }
}

Дебуляция:

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

Код:

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

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

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

2
ответ дан Mohd Asim Suhail 17 August 2018 в 15:17
поделиться

В данном примере значение закрытой переменной '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

0
ответ дан ShAkKiR 17 August 2018 в 15:17
поделиться

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

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

1
ответ дан stusmith 17 August 2018 в 15:17
поделиться

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

Закрытие - одна из самых мощных функций 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>

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

0
ответ дан Sunny S.M 17 August 2018 в 15:17
поделиться

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

function makeAdder(x) {

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

var addFive = makeAdder(5);

console.assert(addFive(2) === 7); 
console.assert(addFive(-5) === 0);
1
ответ дан Tom 17 August 2018 в 15:17
поделиться
  • 1
    Это тип примера, который не помогает людям понять закрытие или то, на что они хороши, на мой взгляд. Сколько раз вы когда-либо писали закрытие, чтобы возвращать функцию для добавления чисел, кроме как в качестве примера? – Mohamad 2 November 2015 в 02:14

В шаблоне модуля JavaScript используются замыкания. Это хороший шаблон, позволяющий иметь что-то похожее «публичные» и «частные» варны.

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 );

    }
  };

})();
1
ответ дан Tomasz Grabowski 17 August 2018 в 15:17
поделиться

Большая часть кода, который мы пишем в интерфейсе 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

0
ответ дан Usman 17 August 2018 в 15:17
поделиться
  • 1
    Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и / или почему оно решает проблему, улучшит долгосрочную ценность ответа. – Donald Duck 3 March 2017 в 13:04
  • 2
    этот пример, как мне кажется, может быть реализован без закрытия через стандартную функцию. Я пытаюсь найти пример того, что НЕ МОЖЕТ быть реализовано без закрытия – Zach Smith 5 May 2017 в 16:26
Другие вопросы по тегам:

Похожие вопросы: