Закрытие Javascript и побочные эффекты на простом английском? (по отдельности) - PullRequest
24 голосов
/ 15 ноября 2011

Я читал некоторые книги по JavaScript и всегда слышал о замыканиях и побочных эффектах. Почему-то я не могу понять, кто они на самом деле. Может кто-нибудь объяснить мне, что они на простом английском плюс примеры? (как вы объясняли это кому-то с уровнем программирования графического дизайнера).

Ответы [ 5 ]

33 голосов
/ 15 ноября 2011

Побочные эффекты - более простая концепция. «Чистая функция» - это функция, которая отображает свои входные значения в выходные значения function plus(x, y) { return x + y; }. «Побочным эффектом» является любой эффект, отличный от этого возвращаемого значения. Так, например:

function plusWithSideEffects(x, y) { alert("This is a side effect"); return x + y; } 

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

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

6 голосов
/ 15 ноября 2011

Функции с побочными эффектами делают что-то кроме возврата значения (хотя они могут делать это также). Если вы можете заменить все вызовы функций для заданных аргументов значением этих аргументов, и программа будет вести себя одинаково, побочных эффектов не будет. Для этого необходимо, чтобы функция всегда возвращала одно и то же значение для заданных аргументов.

То есть, предположим, f(1,2) == 12. Если вы всегда можете заменить f(1,2) на 12 и программа будет вести себя одинаково, то f не будет иметь побочных эффектов для этих аргументов. С другой стороны, если в одном месте f(1,2) == 12, а в другом f(1,2) == 13, то f имеет побочные эффекты. Аналогичным образом, если программа перестала отправлять электронное письмо после замены f(1,2) на 12, то f имеет побочные эффекты. Обычно, если f(x,y) == z (где z зависит от x и y) и вы всегда можете заменить каждый вызов f(x,y) на z, то f не имеет побочных эффектов.

Некоторые простые функции с побочными эффектами:

// doesn't always return the same value
function counter() {
    // globals are bad
    return ++x;
}
// omitting calls to `say` change logging behavior
function say(x) {
    console.log(x);
    return x;
}
4 голосов
/ 15 ноября 2011

Side-эффект:

Думайте о побочном эффекте как о чем-то, что делает две вещи одновременно. Например:

Классический пример побочного эффекта:

var i = 1;
var j = i++;

Побочный эффект происходит при i++. Здесь происходит то, что j становится 1 , а затем i увеличивается и становится равным 2. Другими словами, произошли две вещи, и побочным эффектом стало то, что i стало 2.

Закрытие:

Визуализируйте цепочку ссылок следующим образом: <> <> <> <> <> <> <>. Представьте себе, что имя этой цепочки ссылок называется scope range . Затем представьте, что все эти ссылки соединяют объекты вместе следующим образом: <> object <> object <> object <>. Теперь имейте в виду следующее:

(1) Все цепочки областей действия начинаются с глобального объекта .

(2) Когда функция определена, цепочка областей действия для этой функции сохраняется .

(3) Когда вызывается функция, она создает новый объект и добавляет его в цепочку областей действия.

Теперь, пожалуйста, посмотрите на следующий пример:

function counter () { // define counter
                   var count = 0;
                   return function () { return count + 1;}; // define anonymous function
                   };
var count = counter(); // invoke counter

В этом примере, когда определено counter(), цепочка областей действия для счетчика выглядит следующим образом: <> глобальный объект <>. Затем, когда вызывается counter(), цепочка областей действия выглядит следующим образом: <> глобальный объект <> счетчик объекта <>. После этого функция без имени (называемая анонимной функцией) внутри счетчика определяется и вызывается. Цепочка областей действия для анонимной функции после ее вызова выглядит следующим образом: <> глобальный объект <> счетчик объекта <> объект анонимной функции <>

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

Однако в приведенном выше примере, когда функции возвращаются, объекты, созданные при вызове, отбрасываются, так что в действительности нет никакого смысла. Теперь посмотрим на следующее:

function counter () { // define counter
                   var count = 0;
                   function f() { return count + 1;}; // define f
                   return f; // return f
                   };
var count = counter(); // invoke counter

В этом примере я возвращаю функцию с именем f и назначаю ее переменной count. Теперь переменная count содержит ссылку на всю цепочку областей действия и не сбрасывается. Другими словами, переменная count хранит цепочку областей действия следующим образом: <> глобальный объект <> счетчик объекта <> объект анонимной функции <>. Это сила замыканий, вы можете хранить ссылку на цепочку областей действия и называть ее так: count().

0 голосов
/ 28 июня 2015

Я новичок в JavaScript и не буду пытаться говорить о замыканиях. Однако мое нововведение в JavaScript заставляет меня хорошо понимать использование побочных эффектов, которые невозможны в моем обычном языке программирования (Erlang).

Побочные эффекты кажутся обычным способом изменения состояния в JavaScript. Взять, к примеру, этот пример с сайта w3cschools.com:

<script>
function myFunction() {
    document.getElementById("demo").innerHTML = "Paragraph changed.";
}
</script>

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

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

0 голосов
/ 15 ноября 2011

Exemple

function outer() {
    var outerVar;

    var func = function() {
        var innerVar
        ...
        x = innerVar + outerVar
    }
    return func
}

Когда внешний () умирает, функция func () продолжает работать, и это практично

...