2016-05-13 12 views
6

Czy ktoś mógłby mi wyjaśnić, jaka jest różnica między tymi skryptami poniżej? Pierwszy z nich znajduje się tutaj w Stack Overflow, drugi to moja własna wersja, którą lepiej rozumiem, ale nie działa. Dlaczego to nie działa po drodze?Zapętlanie funkcji JavaScript

1.

(function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
})(); 

2.

function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
    blink(); 
} 
blink(); 
+0

Drugi rzuca stackoverflow wyjątek. Nie powinien sam siebie nazywać. – Bergi

Odpowiedz

11

Pierwszym przykładem jest wyrazem Natychmiast-Wykonano Funkcja (IIFE). Jest to funkcja, która natychmiast wykonuje się po stworzeniu. IIFE to popularny wzorzec projektowania JavaScript używany przez większość popularnych bibliotek (jQuery, Backbone.js, Modernizr, itp.) W celu umieszczenia całego kodu biblioteki w zasięgu lokalnym.

W ES6 to może być zapisane za pomocą Arrow function jeśli chcesz .blinkMe migać tylko raz:

(() => $('.blinkMe').fadeOut(500).fadeIn(500))(); 

Można łańcuchowe tyle fadeIn i fadeOut funkcje jak chcesz oczywiście. Jeśli chcesz, aby pętla była nieskończona, sugerowałbym sposób IIFE.

Więcej informacji o IIFE here.


O twoim drugim przykładzie. Wywołujesz funkcję wewnątrz swojej własnej funkcji (zwanej również pętlą rekursywną). W twoim przypadku tworzy to nieskończoną pętlę, dlatego nie działa. Wyjąć blink(); wewnątrz funkcji i będzie działać:

function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
} 
blink(); 

Poza tym z javascript można również rozwiązać ten problem z animacjami CCS3. Animacje CSS3 są uruchamiane w osobnym wątku. Jest to rozwiązanie bez jQuery:

(function blink() { 
 
    document.getElementsByClassName('blinkMe')[0].className += ' blinkActive'; 
 
})(); 
 

 
// Arrow function: 
 
//(() => document.getElementsByClassName('blinkMe')[0].className += ' blinkActive')();
.blinkMe { 
 
    width: 80px; 
 
    height: 80px; 
 
    background: deepskyblue; 
 
} 
 
.blinkActive { 
 
    -webkit-animation: blink 1s infinite; 
 
    animation: blink 1s infinite; 
 
} 
 
@-webkit-keyframes blink { 
 
    0%, 100% { opacity: 1; } 
 
    50% { opacity: 0; } 
 
} 
 
@keyframes blink { 
 
    0%, 100% { opacity: 1; } 
 
    50% { opacity: 0; } 
 
}
<div class="blinkMe"></div>

nie wiem ile elementy chcesz migać na swojej stronie, jeśli jest to tylko jeden z elementów można użyć zamiast identyfikatorów klas. Należy pamiętać, że reguła @keyframes nie jest obsługiwana w IE9 lub wcześniejszych wersjach i Opera Mini: Link.

+0

poprawić ... Sądzę, że ważne jest to, że ten sentense "tutaj kod jest wykonywany raz w swoim własnym zakresie" i dlatego ten wzorzec jest często używany przez wtyczki jQuery. – daremachine

+0

@daremachine Zaktualizowałem swoją odpowiedź z dodatkowymi informacjami. – Patrick2607

+1

"W twoim przypadku tworzy to nieskończoną pętlę, dlatego to nie działa" o nieskończonej pętli nie jest prawdą. Poprawne wersje to nieskończone pętle (w przeciwnym razie przestałby migać). Niepoprawna wersja jest pętlą wykładniczą, dlatego uległa awarii. –

7

Pierwszy to IIFE. Oznacza to, że funkcja jest natychmiast wywoływana (wykonywana) po jej zadeklarowaniu. Nie jest dołączone do globalnego obiektu okna, więc nie zanieczyszcza go.

Druga funkcja jest rekursywna wykładniczo. Za każdym uruchomieniem wywołuje się jeszcze dwa razy, raz jako wywołanie zwrotne dla metody jquery fadeIn i jeszcze raz w treści funkcji.

6

Linia $('.blinkMe').fadeOut(500).fadeIn(500, blink); już nazywa się blink po zakończeniu. Zatem wywołanie z powrotem blink() przypomina dwukrotność wywoływanej funkcji (a nawet więcej przy każdym połączeniu). Więc to wezwanie było problemem.

EDYCJA: Ale, jak właśnie dowiedziałem się dzisiaj, timery nie są wykonywane w innym wątku w JavaScript.Tak więc, blink() w ramach funkcji blink przyjmuje wszystkie ramki wykonań, a wywołanie zwrotne blink nigdy nie jest wywoływane, ale nadal jest rejestrowane do wywołania. Testowałem, dodając maksymalną liczbę iteracji, aby można było wywołać w nim blink().

function blink() { 
 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
 
    //blink(); 
 
} 
 
blink();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> 
 
<span class="blinkMe">Blinking</span>

6

W tym fragmencie, nazwany funkcja jest tworzona, a następnie natychmiast wykonywana raz w Immediately-Invoked Function Expression. Nazwa funkcji jest dostępna tylko dla siebie, więc można ją ponownie wywołać w zamknięciu treści funkcji, w tym przypadku jako wywołanie zwrotne funkcji fadeIn.

(function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
})(); 


W tym fragmencie, nazwany funkcja jest tworzona, i nazwie. Dodatkowo funkcja ponownie wywołuje samą siebie, co spowoduje nieskończoną rekursję, przez co nie powiedzie się. W przeciwieństwie do ostatniego fragmentu, blink będzie dostępny również poza samym zamknięciem funkcji.

function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
    blink(); 
} 
blink(); 

Zdejmowanie blink() połączenia wewnątrz funkcji się następująco pozwoli funkcjonować prawie identyczne, z wyjątkiem różne w blink zakresie.

function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
} 
blink(); 
2

To jest funkcja rekursywna (animacja).

Zgodnie z jQuery docs, fadeIn() przyjmuje dwa argumenty: duration (w ms) i complete. Drugi argument to funkcja wywoływana po zakończeniu animacji. Może być sobą lub inną funkcją.

W drugiej funkcji ponownie dzwonisz blink() ... ale drugi i trzeci nigdy nie nadchodzą. Najlepszy sposób jest pierwszy.

2

Twoja funkcja działa, ale Navigator blokuje ją z powodu zbyt dużej rekurencji. bo jesteś callling blink() zaraz po fadeIn po prostu spróbować,

function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
    //remove this call which causes too many recursions 
    //blink(); 
} 
//then call the method 
blink();