06
Fonctions Avancées
Types, Closures, this & Patterns
Les fonctions sont des citoyens de première classe en JS. Elles peuvent être passées, retournées, et stockées comme n'importe quelle valeur.
🎯 Les 6 Types de Fonctions
1️⃣ Function Declaration
function greet(name) {
return `Hello ${name}`;
}
// ✅ Hoisted (disponible avant)
// ✅ Nommée (stack traces)
Quand : Fonctions réutilisables, hoisting souhaité
2️⃣ Function Expression
const greet = function(name) {
return `Hello ${name}`;
};
// ❌ Pas hoisted
// ✅ Assignable à variable
Quand : Callbacks, assignation conditionnelle
3️⃣ Arrow Function
const greet = (name) => `Hello ${name}`;
// ✅ Syntaxe concise
// ✅ Lexical this (hérite du parent)
// ❌ Pas de 'arguments'
Quand : Callbacks, méthodes array, pas besoin de `this`
4️⃣ IIFE (Immediately Invoked)
(function() {
const secret = "privé";
console.log(secret);
})();
// ✅ Scope isolé
// ✅ Exécution immédiate
Quand : Isolation de scope, module pattern (legacy)
5️⃣ Async Function
async function fetchData() {
const res = await fetch(url);
return res.json();
}
// ✅ Retourne toujours Promise
// ✅ Syntaxe await
Quand : Opérations asynchrones (API, I/O)
6️⃣ Generator Function
function* count() {
yield 1;
yield 2;
yield 3;
}
// ✅ Pause/Resume avec yield
// ✅ Itérable
Quand : Itération lazy, state machines
🔒 Closures : Mémoire Persistante
Une closure permet à une fonction d'accéder aux variables de son scope parent, même après que ce parent ait terminé son exécution.
📦 Visualisation Mémoire
function createCounter() {
let count = 0; // ← Variable capturée
return function() {
count++;
return count;
};
}
const counter = createCounter();
counter(); // 1
counter(); // 2 (count persiste !)
🌍 Global Scope
counter: function
📦 createCounter() Scope (Fermé mais accessible)
count: 2
🔒 Fonction retournée (Closure)
Accède à
count via la closure
chain🎯 Le Mystère de `this`
La valeur de `this` dépend de comment la fonction est appelée, pas où elle est définie.
✅ Arrow Function (Lexical this)
const obj = {
name: "Alice",
greet: () => {
// this = window/global
console.log(this.name);
}
};
// ⚠️ Arrow hérite du parent
✅ Regular Function
const obj = {
name: "Alice",
greet: function() {
// this = obj
console.log(this.name);
}
};
obj.greet(); // "Alice"
// Les 4 façons de lier 'this'
// 1. Appel méthode : this = objet
obj.method();
// 2. Appel simple : this = undefined (strict) ou window
fn();
// 3. call/apply : this = premier argument
fn.call(customThis, arg1, arg2);
fn.apply(customThis, [arg1, arg2]);
// 4. bind : crée nouvelle fonction avec this fixé
const boundFn = fn.bind(customThis);
boundFn();
🎮 This Playground
Testez comment `this` change selon le contexte d'appel.
obj.method()
fn()
Arrow Function
fn.call(custom)
fn.bind(custom)
Cliquez sur un bouton pour tester
🧪 Pure Functions vs Side Effects
❌ Impure (Side Effects)
let total = 0;
function add(n) {
total += n; // Modifie état externe
return total;
}
// ❌ Non prédictible
// ❌ Difficile à tester
✅ Pure (Prédictible)
function add(a, b) {
return a + b; // Pas d'effet de bord
}
// ✅ Même input = même output
// ✅ Testable
// ✅ Cacheable
Best Practice : Privilégiez les fonctions pures. Elles sont plus faciles à tester,
débugger, et optimiser (memoization).