2010-04-18 3 views
4

Pendant que je lisais le livre Javascript: The Good Parts. Je ne comprends pas le morceau de soufflet de code:Questions de fermeture de Javascript

On peut généraliser ce en faisant une fonction qui nous aide à faire memoized fonctions. La fonction mémoizer prendra un tableau mémo initial et la fonction fondamentale . Il renvoie une fonction shell qui gère le mémo et appelle la fonction fondamentale selon les besoins. Nous passons la coquille fonction et les paramètres de la fonction à la fonction fondamentale:

var memoizer = function (memo, fundamental) { 
    var shell = function (n) { 
     var result = memo[n]; 
     if (typeof result !== 'number') { 
      result = fundamental(shell, n); 
      memo[n] = result; 
     } 
     return result; 
    }; 
    return shell; 
}; 

Nous pouvons maintenant définir fibonacci avec le memoizer, fournissant la note initiale tableau et la fonction fondamentale:

var fibonacci = memoizer([0, 1], function (test, n) { 
    return test(n - 1) + test(n - 2); 
}); 

Ma question est quelle est la fonction de test? Quand est-il défini et invoqué? Cela me semble très confus. Aussi je pense que cette déclaration: memo[n] = result; est inutile. Veuillez corriger si j'ai tort.

+0

Whoa. En tant que personne avec très peu de connaissances fonctionnelles en programmation, ce code m'a tout simplement ému. C'est tellement intelligent! – dmb

+0

related: [Explication sur l'exemple "JavaScript - the Good Parts" (section 4.15)?] (Https://stackoverflow.com/questions/3798858/explanation-on-javascript-the-good-parts-example-section-4 -15) – Bergi

Répondre

1

L'instruction memo[n] = result; stocke le nombre nouvellement calculé dans le tableau de mémoisation ou le cache. La fonction test est un argument de la fonction à mémoriser et est définie et transmise par le memoizer. Lorsqu'il est appelé, il vérifie si la valeur à calculer a déjà été mise en cache. Si c'est le cas, il le renvoie du cache. Sinon, il recalcule à nouveau.

Après tout le code ci-dessus est exécuté, nous obtenons quelque chose comme ça en mémoire (mais avec le tableau memo et orig_fibonacci encapsulé):

var memo = [0, 1]; 

function fibonacci(n) { 
    var result = memo[n]; 
    if (typeof result != 'number') { 
    result = orig_fibonacci(n); 
    memo[n] = result; 
    } 
    return result; 
} 

function orig_fibonacci(n) { 
    return fibonacci(n - 1) + fibonacci(n - 2); 
} 
4

C'était un extrait de code amusant à lire :)

Vous savez probablement que memoization stocke le résultat d'une fonction, de sorte que la prochaine fois que la fonction est appelée, elle n'a pas à calculer la réponse, elle peut simplement la rechercher.

Nous avons donc besoin de stocker des réponses pour la fonction fibonacci qui prend un int et retourne un int.

var fibonacci = memoizer([0, 1], function (test, n) { 
    return test(n - 1) + test(n - 2); 
}); 

demande memoizer avec un réseau de mémoire initial, fib de mappage (0) -> 0 et fib (1) -> 1.

Le reste définit une fonction sans nom qui prend une fonction et un nombre. 'test' est un mauvais nom, il devrait être "recursive_fibonacci_helper" :)

Cette fonction sans nom devient le paramètre "fondamental". La fonction memoizer renvoie une fonction (shell) qui prend un argument int. Cela devient finalement la fonction fibonacci. Donc, quand quelqu'un dit "fibonacci (5)". Ils appellent vraiment "shell (5)". La partie importante des fermetures est que "fondamental" et "mémo" sont déjà liés.

Alors, que fait 'shell'?

Il lève les yeux dans le tableau pour voir s'il a déjà calculé une réponse pour cette entrée. S'il voit une réponse (== 'nombre'), il le renvoie. Sinon, il le calcule et le stocke dans la table de mémo. memo[n] = result stocke actuellement le résultat calculé dans la table mémoization.