Преодолевая JavaScript-интервью: что такое замыкания? | Эрик Эллиотт

внешний интерфейс JavaScript API опрос
Преодолевая JavaScript-интервью: что такое замыкания? | Эрик Эллиотт

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

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

Не оглядывайся, это ты. Вы действительно понимаете, как создать серьезное приложение на JavaScript? Вы действительно понимаете, что скрывается за кодом или как работает приложение? Я сомневаюсь в этом. Если вы не можете решить даже проблему закрытия, это немного скучно.

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

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

Мне все равно, если интервьюер знает слово «закрытие» или его профессиональное определение. Я просто хочу выяснить, понимают ли они обоснование. Если они этого не сделают, это обычно означает, что эти интервьюеры не имеют большого количества опыта, наращивающих фактические приложения JavaScript.

Если вы не можете ответить на этот вопрос, вы просто младший разработчик. Независимо от того, как долго вы этим занимаетесь.

Чтобы быстро понять следующее: можете ли вы придумать общий сценарий для двух закрытий?

Что такое закрытие?

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

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

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

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

Примеры использования закрытия

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

«Программируйте интерфейс, не программируйте реализацию».Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения

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

const getSecret = (secret) => {
  return {
    get: () => secret
  };
};

test('Closure for object privacy.', assert => {
  const msg = '.get() should have access to the closure.';
  const expected = 1;
  const obj = getSecret(1);

  const actual = obj.get();

  try {
    assert.ok(secret, 'This throws an error.');
  } catch (e) {
    assert.ok(true, `The secret var is only available
      to privileged methods.`);
  }

  assert.equal(actual, expected, msg);
  assert.end();
});

В приведенном выше примереget()метод определен вgetSecret()Scope, что позволяет ему получить доступ к любомуgetSecret()переменная в , так что это авторизованный метод. В этом примере он имеет доступ к параметрамsecret.

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

const secret = (msg) => () => msg;
// Secret - creates closures with secret messages.
// https://gist.github.com/ericelliott/f6a87bc41de31562d0f9
// https://jsbin.com/hitusu/edit?html,js,output

// secret(msg: String) => getSecret() => msg: String
const secret = (msg) => () => msg;

test('secret', assert => {
  const msg = 'secret() should return a function that returns the passed secret.';

  const theSecret = 'Closures are easy.';
  const mySecret = secret(theSecret);

  const actual = mySecret();
  const expected = theSecret;

  assert.equal(actual, expected, msg);
  assert.end();
});

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

Применение функции:Процедура, которая передает параметры функции и получает возвращаемое значение.

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

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

partialApply(targetFunction: Function, ...fixedArgs: Any[]) =>
  functionWithFewerParams(...remainingArgs: Any[])

Если вы хотите глубже понять приведенную выше форму, вы можете увидетьздесь.

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

Вот пример для иллюстрации, предположим, что у вас есть функция, которая суммирует два числа:

const add = (a, b) => a + b;

Теперь вы хотите получить функцию, которая добавляет 10 к любому переданному ей аргументу, мы можем назвать ее какadd10().add10(5)Результат должен быть15. нашpartialApply()Функция может сделать это:

const add10 = partialApply(add, 10);
add10(5);

В этом примере параметр10Предварительно назначен через область закрытияadd(), чтобы мы получилиadd10().

Теперь посмотрим, как добитьсяpartialApply():

// Generic Partial Application Function
// https://jsbin.com/biyupu/edit?html,js,output
// https://gist.github.com/ericelliott/f0a8fd662111ea2f569e

// partialApply(targetFunction: Function, ...fixedArgs: Any[]) =>
//   functionWithFewerParams(...remainingArgs: Any[])
const partialApply = (fn, ...fixedArgs) => {
  return function (...remainingArgs) {
    return fn.apply(this, fixedArgs.concat(remainingArgs));
  };
};


test('add10', assert => {
  const msg = 'partialApply() should partially apply functions'

  const add = (a, b) => a + b;

  const add10 = partialApply(add, 10);


  const actual = add10(5);
  const expected = 15;

  assert.equal(actual, expected, msg);
});

Как видите, он просто возвращает функцию, доступ к которой осуществляется через замыкание, переданное вpartialApply()функциональныйfixedArgsпараметр.

твоя очередь попробовать

Для чего вы используете замыкания? Если у вас есть любимый вариант использования, дайте мне несколько примеров и дайте мне знать в комментариях.