Каково точное определение закрытия?

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

Это возвращает массив данного объекта с собственными перечисляемыми значениями свойств. Вы получите те же значения, что и при использовании цикла for in, но без свойств в прототипе. Этот пример, вероятно, прояснит ситуацию:

function person (name) {
  this.name = name;
}

person.prototype.age = 5;

let dude = new person('dude');

for(let prop in dude) {
  console.log(dude[prop]);     // for in still shows age because this is on the prototype
}                              // we can use hasOwnProperty but this is not very elegant

// ES6 + 
console.log(Object.values(dude));
// very concise and we don't show props on prototype
17
задан J-16 SDiZ 8 July 2009 в 01:40
поделиться

6 ответов

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

Из Википедии

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

6
ответ дан 30 November 2019 в 10:54
поделиться

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

Вот как будет работать закрытие:

function makeCounter( int x )
{
  return int counter() {
    return x++;
  }
}

c = makeCounter( 3 );
printf( "%d" c() ); => 4
printf( "%d" c() ); => 5
d = makeCounter( 0 );
printf( "%d" d() ); => 1
printf( "%d" c() ); => 6

Другими словами, разные вызовы makeCounter () производят разные функции с их собственными привязками переменных в их лексическое окружение, которое они «закрыли».

Изменить: я думаю, что такие примеры упрощают понимание замыканий, чем определения, но если вам нужно определение, я бы сказал: «Замыкание - это комбинация функции и Среда. Среда содержит переменные, которые определены в функции, а также те, которые видны функции при ее создании. Эти переменные должны оставаться доступными для функции, пока функция существует ».

22
ответ дан 30 November 2019 в 10:54
поделиться

Отличный вопрос! Учитывая, что один из принципов ООП ООП заключается в том, что у объектов есть поведение, а также данные, замыкания представляют собой особый тип объектов, потому что их самая важная цель - это их поведение. Тем не менее, что я имею в виду, когда говорю об их «поведении»?

(Многое из этого заимствовано из "Groovy in Action" Дирка Конига, потрясающей книги)

На простейшем уровне закрытие - это просто некоторый код, который обернут, чтобы стать андрогинным объектом / методом . Это метод, потому что он может принимать параметры и возвращать значение, но это также и объект, в котором вы можете передавать ссылку на него.

Говоря словами Дирка, представьте себе конверт, внутри которого лежит лист бумаги. Типичный объект имеет переменные и их значения, записанные на этой бумаге, но вместо этого в закрытии будет список инструкций. Допустим, в письме говорится: «Отдайте этот конверт и письмо своим друзьям».

In Groovy: Closure envelope = { person -> new Letter(person).send() }
addressBookOfFriends.each (envelope)

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

Некоторые подробности: Область действия: область действия закрытия - это данные и элементы, к которым можно получить доступ в ней. Возврат из замыкания: замыкания часто используют механизм обратного вызова для выполнения и возврата из самого себя. Аргументы: если замыкание должно принимать только 1 параметр, Groovy и другие языки предоставляют имя по умолчанию: «it», чтобы ускорить кодирование. Так, например, в нашем предыдущем примере:

addressBookOfFriends.each (envelope) 
is the same as:
addressBookOfFriends.each { new Letter(it).send() }

Надеюсь, это то, что вы ищете!

1
ответ дан 30 November 2019 в 10:54
поделиться

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

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

0
ответ дан 30 November 2019 в 10:54
поделиться

Чтобы получить точное определение , я предлагаю посмотреть его статью в Википедии . Это особенно хорошо. Я просто хочу прояснить это на примере.

Предположим, что этот фрагмент кода C # (который должен выполнять поиск И в списке):

List<string> list = new List<string> { "hello world", "goodbye world" };
IEnumerable<string> filteredList = list;
var keywords = new [] { "hello", "world" };
foreach (var keyword in keywords)
    filteredList = filteredList.Where(item => item.Contains(keyword));

foreach (var s in filteredList)  // closure is called here
    Console.WriteLine(s);

Распространенная ошибка в C # - делать что-то вроде который. Если вы посмотрите на лямбда-выражение внутри Where , вы увидите, что оно определяет функцию, поведение которой зависит от значения переменной на сайте ее определения. Это похоже на передачу функции самой переменной , а не значения этой переменной . Фактически, когда это закрытие вызывается, оно извлекает значение переменной keyword на тот момент. Результат этого образца очень интересен. Он выводит как «привет, мир», так и «до свидания, мир», чего мы не хотели. Что произошло? Как я уже сказал выше, функция, которую мы объявили с лямбда-выражением, является закрытием над ключевым словом переменной , поэтому происходит следующее:

filteredList = filteredList.Where(item => item.Contains(keyword))
                           .Where(item => item.Contains(keyword)); 

и во время выполнения закрытия ] ключевое слово имеет значение "мир", поэтому мы, по сути, фильтруем список пару раз с одним и тем же ключевым словом. Решение:

foreach (var keyword in keywords) {
    var temporaryVariable = keyword;
    filteredList = filteredList.Where(item => item.Contains(temporaryVariable));
}

Так как временная переменная ограничена областью тела цикла foreach , на каждой итерации это разные переменные. Фактически, каждое замыкание будет привязано к отдельной переменной (это разные экземпляры timeVariable на каждой итерации). На этот раз это Я выдам правильные результаты («привет, мир»):

filteredList = filteredList.Where(item => item.Contains(temporaryVariable_1))
                           .Where(item => item.Contains(temporaryVariable_2));

, в котором временная переменная_1 имеет значение «привет», а временная переменная_2 имеет значение «мир» на момент закрытия исполнение.

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

Это также важный побочный эффект закрытия.

Это также важный побочный эффект закрытия.

12
ответ дан 30 November 2019 в 10:54
поделиться

Замыкание - это метод реализации для представления процедур / функций с локальным состоянием. Один из способов реализации замыканий описан в SICP. В любом случае я изложу суть.

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

// This is some C like language that has first class functions and closures.
function accumulator(counter) {
    return (function() { return ++counter; });
}

Что произойдет, когда мы оценим следующую строку?

accum1 = accumulator(0);

Сначала создается новая среда и целочисленный объект (для счетчик ) привязан к 0 в своем первом кадре. Возвращаемое значение, представляющее собой новую функцию, привязано к глобальной среде. Обычно новая среда будет собираться мусором после того, как функция оценка окончена. Здесь этого не произойдет. аккумулятор1 содержит ссылку на него, так как ему требуется доступ к счетчику переменной . Когда вызывается аккумулятор1 , он увеличивает значение счетчика counter в указанной среде. Теперь мы можем вызвать аккумулятор1 функцию с локальным состоянием или закрытием.

В моем блоге я описал несколько практических применений закрытий. http://vijaymathew.wordpress.com . (См. Сообщения «Опасные конструкции» и «О передаче сообщений»).

3
ответ дан 30 November 2019 в 10:54
поделиться
Другие вопросы по тегам:

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