8

Зачем оборачивать блоки кода на JS в самовыполняющиеся функции?

  • 2
    Пример приведите, пожалуйста. – Kromster Dec 01 '15 at 17:54
  • 2
    Чтобы переменные оставались внутри функции и не захламляли внешний scope: fiddle. – Regent Dec 01 '15 at 18:07
  • @VladD всё-таки хотелось бы получить пример от автора, чтобы быть уверенным, что речь вообще именно об этом. Надо было эту оговорку в комментарий свой предыдущий добавить. – Regent Dec 01 '15 at 18:16
  • @Regent: Ну, вроде бы самовыполняющаяся функция — устоявшийся термин. – VladD Dec 01 '15 at 18:17
  • И тема об областях видимости важна, т. к. одно из фундаментальных отличий js от других языков. – VladD Dec 01 '15 at 18:18
  • А пример чего вы хотите получить? Самовыполняющейся функции? – VladD Dec 01 '15 at 18:18
  • Такой вопрос у меня был в домашнем задании. Примера нет. И информацию найти не получается. – Gavrenko Katerina Dec 01 '15 at 18:24
  • 1
    @GavrenkoKaterina: Вопрос на самом деле касается одного из основополагающих принципов javascript. – VladD Dec 01 '15 at 18:28
  • 1
    @VladD я скромный (немногим более развёрнутый, чем в комментарии) ответ почти написал, но вот полный и развёрнутый ответ по поводу замыканий и областей видимости вряд ли потяну. – Regent Dec 01 '15 at 18:31
  • Гуглите IIFE ;) – Dmitriy Simushev Dec 01 '15 at 18:32
  • http://stackoverflow.com/questions/8228281/what-is-the-function-construct-in-javascript – Grundy Dec 01 '15 at 18:36
  • 1
    @Regent запостите, а потом правками улучшите. Или запостите как вики, тогда и другие дополнят – Kromster Dec 01 '15 at 18:36

1 Answers1

15

Переменные, объявленные внутри функции, являются локальными (находятся в её области видимости). Это даёт как минимум 3 полезных момента:

  1. "Снаружи" не "достучаться" до того, что объявлено внутри функции.
  2. Не получится случайно затереть глобальную переменную, объявив переменную с таким же именем внутри функции.
  3. Глобальная область видимости не "захламляется" данными, которые не должны быть глобальными.

Самовыполняющаяся функция (Immediately-Invoked Function Expression, IIFE) позволяет воспользоваться этими преимуществами, не создавая глобальную функцию.

var x = 1;
(function() {
    var x = 2;
    var y = 3;
    console.log("In: " + x); //In: 2
    console.log("In: " + y); //In: 3
})();
console.log("Out: " + x); //Out: 1
console.log("Out: " + y); //ReferenceError: y is not defined 

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

var test = (function() {
    var count = 0;
    return function() {
        count++;
        console.log("Count: " + count);
    };
})();
test(); //Count: 1
test(); //Count: 2
console.log(count); //ReferenceError: count is not defined

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


Также самовыполняющаяся функция может "помочь" с сохранением промежуточных значений данных при асинхронном выполнении кода.

Например:

for (var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000 * i);
}

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

Если же обернуть setTimeout в функцию и передавать ей i в качестве аргумента, то вывод будет от 0 до 9:

for (var i = 0; i < 10; i++) {
    (function(i) {
        setTimeout(function() {
            console.log(i);
        }, 1000 * i);
    })(i);
}

В данном случае переменная i в setTimeout уже не является глобальной переменной и не зависит от её изменений. Однако тут не нужно забывать о том, что если переменная является объектом, то изменение значения поля объекта "снаружи" приведёт и к изменению значения поля объекта "внутри".

Regent
  • 19,134