Zagnieżdżona funkcja JavaScript

97

Mam kawałek kodu javascript, którego po prostu nie rozumiem:

function dmy(d) {
    function pad2(n) {
        return (n < 10) ? '0' + n : n;
    }

    return pad2(d.getUTCDate()) + '/' +
       pad2(d.getUTCMonth() + 1) + '/' +
       d.getUTCFullYear();
}

function outerFunc(base) {
    var punc = "!";

    //inner function
    function returnString(ext) {
       return base + ext + punc;
    }

    return returnString;
}

Jak można zdefiniować funkcję w ramach innej funkcji? Czy możemy wywołać pad2 () spoza funkcji my ()?

Proszę, rzuć na to trochę światła. Dzięki

Tomasz
źródło
13
funkcje można tworzyć wewnątrz funkcji. To jest całkowicie słuszne.
0x499602D2

Odpowiedzi:

141

Funkcje to inny typ zmiennych w JavaScript (oczywiście z pewnymi niuansami). Utworzenie funkcji w ramach innej funkcji zmienia zakres funkcji w taki sam sposób, jak zmieniałby zakres zmiennej. Jest to szczególnie ważne w przypadku użycia z zamknięciami w celu zmniejszenia całkowitego zanieczyszczenia globalnej przestrzeni nazw.

Funkcje zdefiniowane w innej funkcji nie będą dostępne poza funkcją, chyba że zostaną dołączone do obiektu, który jest dostępny poza funkcją:

function foo(doBar)
{
  function bar()
  {
    console.log( 'bar' );
  }

  function baz()
  {
    console.log( 'baz' );
  }

  window.baz = baz;
  if ( doBar ) bar();
}

W tym przykładzie funkcja baz będzie dostępna do użycia po uruchomieniu foofunkcji, ponieważ została nadpisana window.baz. Funkcja paska nie będzie dostępna dla żadnego kontekstu innego niż zakresy zawarte w foofunkcji.

jako inny przykład:

function Fizz(qux)
{
  this.buzz = function(){
    console.log( qux );
  };
}

FizzFunkcja została zaprojektowana jako konstruktor tak, że po uruchomieniu, przypisuje się buzzfunkcję do nowo utworzonego obiektu.

zzzzBov
źródło
Co to jest window.baz = baz? Dlaczego ta linia m? Ke baz jest dostępna?
Ziyang Zhang
@ZiyangZhang, akapit po tym bloku kodu zawiera wyjaśnienie, czy była jakaś konkretna część, która jest niejasna?
zzzzBov
35

Nazywa się to zamknięciem .

Zasadniczo funkcja zdefiniowana w innej funkcji jest dostępna tylko w ramach tej funkcji. Ale może zostać przekazany jako wynik, a następnie ten wynik może zostać wywołany.

To bardzo potężna funkcja. Więcej wyjaśnień można znaleźć tutaj:

javascript_closures_for_dummies.html kopia lustrzana na Archive.org

Tadeck
źródło
13
function x() {}

jest równoważny (lub bardzo podobny) do

var x = function() {}

chyba że się mylę.

Więc nie dzieje się nic zabawnego.

Andreas
źródło
8
Pierwsza składnia zostanie przeniesiona na początek dokumentu. więc możliwe jest wywołanie funkcji „x” przed jej zainicjalizowaniem.
Tom
10
Pierwsza składnia zapewni również znacznie ładniejsze ślady stosu z nazwanymi funkcjami, druga przyprawi o ból głowy
TheZ
@TheZ Myślę, że Chrome niedawno dodał wnioskowanie o nazwie funkcji do debugowania, aby nie odczuwać tego samego bólu głowy, co wcześniej w typowym przypadku.
jinglesthula
@jinglesthula Yes! Chrome dodał to wnioskowanie o nazwie jakiś czas temu i jest to bardzo cenione :)
TheZ,
10

Tworzenie instancji funkcji jest dozwolone wewnątrz i na zewnątrz funkcji. Wewnątrz tych funkcji, podobnie jak zmienne, funkcje zagnieżdżone są lokalne i dlatego nie można ich uzyskać z zewnętrznego zakresu.

function foo() {
    function bar() {
        return 1;
    }
    return bar();
}

foomanipuluje barw sobie. barnie można dotknąć z zakresu zewnętrznego, chyba że jest zdefiniowany w zakresie zewnętrznym.

Więc to nie zadziała:

function foo() {
    function bar() {
        return 1;
    }
}

bar(); // throws error: bar is not defined
0x499602D2
źródło
4

Kiedy deklarujesz funkcję w funkcji, funkcje wewnętrzne są dostępne tylko w zakresie, w którym zostały zadeklarowane, lub w twoim przypadku pad2można je wywołać tylko w dmyzakresie.

Wszystkie istniejące zmienne dmysą widoczne w pad2, ale nie dzieje się na odwrót: D

pedrochaves
źródło
2

Posiadanie funkcji wewnątrz funkcji jest całkowicie normalne w JavaScript (i wielu językach).

Poświęć trochę czasu na naukę języka, nie używaj go, ponieważ jest podobny do tego, co już znasz. Proponuję obejrzeć serię prezentacji YUI Douglasa Crockforda na temat Javascript, ze szczególnym uwzględnieniem Act III: Function the Ultimate (link do pobrania wideo, slajdów i transkrypcji)

Joaquim Rendeiro
źródło
0

function foo() {
  function bar() {
    return 1;
  }
}
bar();

Wystąpi błąd. Ponieważ barjest zdefiniowany wewnątrz foo, barbędzie dostępny tylko w środku foo.
Aby go użyć bar, musisz uruchomić go w środku foo.

function foo() {
  function bar() {
    return 1;
  }
  bar();
}

Justin Liu
źródło