Более новое решение может быть доступно в пакете purrr
. Для вашего точного вопроса вы можете использовать reduce()
отметить малый r по сравнению с base::Reduce
, но вы могли бы полностью устранить проблему, используя map_dfr()
или map_dfc
, которые могли бы предотвратить проблему, сделав карту и уменьшить шаг в одном.
Я использовал замыкания, чтобы делать такие вещи, как:
a = (function () {
var privatefunction = function () {
alert('hello');
}
return {
publicfunction : function () {
privatefunction();
}
}
})();
Как вы можете видеть там, a
теперь является объектом с помощью метода publicfunction
(a.publicfunction()
), который вызывает privatefunction
, который существует только внутри замыкания. Вы не можете называть privatefunction
напрямую (т. Е. a.privatefunction()
), просто publicfunction()
.
Его минимальный пример, но, возможно, вы можете увидеть его использование? Мы использовали это для применения публичных / частных методов.
Закрытие - это полезный способ создания генераторов , последовательность с поправкой по требованию:
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
Ссылки
Здесь у меня есть один простой пример концепции закрытия, который мы можем использовать на нашем сайте электронной коммерции или многих других. Я добавляю ссылку jsfiddle с примером. он содержит небольшой список товаров из 3 предметов и один счетчик корзины.
//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>
Да, это хороший пример полезного закрытия. Вызов 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);
Другим распространенным применением закрытий является связывание 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 с помощью функции » для конкретного примера.
В Mozilla Developer Network имеется раздел о Практических замыканиях .
return function ()...
, код все еще работает нормально. Закрытие не является обязательным
– an earwig
15 August 2015 в 02:47
Этот поток очень помог мне в получении лучшего понимания того, как работают замыкания. С тех пор я сделал некоторые эксперименты по своему собственному опыту и придумал этот довольно простой код, который может помочь некоторым другим людям понять, как закрытие может быть использовано на практике и как использовать закрытие на разных уровнях для поддержания переменных, похожих на статические и / или глобальные переменные без риска их перезаписи или путаницы с глобальными переменными. То, что это делает, - отслеживать нажатия кнопок, как на локальном уровне для каждой отдельной кнопки, так и на глобальном уровне, подсчитывая каждое нажатие кнопки, внося вклад в одну цифру. Примечание. Я не использовал глобальные переменные для этого, что является своего рода точкой упражнения - с обработчиком, который может быть применен к любой кнопке, которая также способствует чему-то глобально.
Пожалуйста, эксперты, дайте мне знать, если я совершил какую-либо плохую практику здесь! Я все еще сам изучаю этот материал.
<!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>
Если вам нравится концепция создания экземпляра класса в объектно-ориентированном смысле (т. е. для создания объекта этого класса), то вы близки к пониманию закрытий.
Подумайте об этом так: когда вы создаете экземпляр двух объектов Person, вы знаете, что переменная-член класса «Имя» не делится между экземплярами; каждый объект имеет свою «копию». Аналогично, когда вы создаете замыкание, свободная переменная («calledCount» в вашем примере выше) привязана к «экземпляру» функции.
Я думаю, что ваш концептуальный скачок немного затруднен тем фактом, что каждая функция / замыкание, возвращаемая функцией warnUser (в стороне: это функция более высокого порядка ), связывает «calledCount» с тем же начальным значением (0), тогда как часто при создании замыканий более полезно передавать разные инициализаторы в функцию более высокого порядка, подобно передаче разных значений конструктору класса.
Итак, предположим, когда «calledCount» достигает определенного значения, которое вы хотите завершить сеанс пользователя; вам могут потребоваться разные значения для этого в зависимости от того, поступает ли запрос из локальной сети или большого плохого интернета (да, это надуманный пример). Чтобы достичь этого, вы могли передавать разные начальные значения для callCount в warnUser (т. Е. -3 или 0?).
. Часть проблемы с литературой - это номенклатура, используемая для их описания («лексический охват») , "свободные переменные"). Не позволяйте этому обмануть вас, затворы более просты, чем казалось ... prima facie; -)
Предположим, вы хотите подсчитать количество нажатий кнопки пользователя на веб-странице. Для этого вы вызываете функцию на 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>
Здесь у меня есть приветствие, которое я хочу сказать несколько раз. Если я создаю закрытие, я могу просто вызвать эту функцию для записи приветствия. Если я не создаю закрытие, я должен передать свое имя за каждый раз.
Без закрытия ( 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();
В языке 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
, но тогда он будет виден пользователям сценария, и они могут даже изменить его, если они захотят, даже не нуждаясь в исходном коде. Однако, поскольку он заключен в анонимную функцию, которая возвращает функцию поиска по дате, она доступна только для функции поиска, поэтому теперь она защищена от несанкционированного доступа.
Пример, который вы даете, является отличным. Закрытие - это механизм абстракции, который позволяет очень осторожно разделить проблемы. Ваш пример - это случай разделения инструментов (подсчета вызовов) на семантику (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; }
}
}
int
?) Последнее, что я проверил, JavaScript был утиным языком. Возможно, вы думали о Java?
– Hello71
5 November 2010 в 02:41
Ссылка: Практическое использование замыканий
На практике замыкания могут создавать элегантные конструкции, позволяющие настраивать различные вычисления, отложенные вызовы, обратные вызовы, создавать инкапсулированные области и т. д.
Пример метода сортировки массивов, который принимает в качестве аргумента функцию 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
Я знаю, что мне очень поздно отвечать на этот вопрос, но это может помочь любому, кто все еще ищет ответ в 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)
}
}
Как вы видите, закрытие помогло реализовать две красивые функции, которые каждый веб-приложение должно обеспечить бесперебойную работу с интерфейсом пользовательского интерфейса.
Надеюсь, это поможет кому-то.
В данном примере значение закрытой переменной '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
Я написал статью некоторое время назад о том, как закрытие может использоваться для упрощения кода обработки событий. Он сравнивает обработку событий ASP.NET с клиентским jQuery.
http://www.hackification.com/2009/02/20/closures-simplify-event-handling-code/
Использование закрытий:
Закрытие - одна из самых мощных функций 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>
В приведенном выше коде переменная имени внешнего функция доступна для внутренних функций, и нет другого способа доступа к внутренним переменным, кроме внутренних функций. Внутренние переменные внутренней функции действуют как безопасные хранилища для внутренних функций. Они содержат «постоянные», но безопасные данные для работы внутренних функций. Функции даже не должны присваиваться переменной или иметь имя. прочитайте здесь для деталей
Мне нравится функция фабрики 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);
В шаблоне модуля 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 );
}
};
})();
Большая часть кода, который мы пишем в интерфейсе 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;