Что практического использования для закрытия в JavaScript? - PullRequest
247 голосов
/ 28 апреля 2010

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

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

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

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

Это, например, этот?

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

Ответы [ 20 ]

2 голосов
/ 10 августа 2015

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

function makeAdder(x) {

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

var addFive = makeAdder(5);

console.assert(addFive(2) === 7); 
console.assert(addFive(-5) === 0);
2 голосов
/ 01 июня 2018

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

Шаблон модуля 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 );

    }
  };

})();
2 голосов
/ 10 августа 2015

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

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

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

1 голос
/ 24 октября 2017

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

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

<!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>
1 голос
/ 28 апреля 2010

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

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

0 голосов
/ 21 мая 2018

В данном примере значение вложенной переменной '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 голосов
/ 03 марта 2017

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

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

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

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

[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
0 голосов
/ 28 июня 2013

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

    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

Ссылки

...