Mis à jour le

🟨
Senior 25 questions • JavaScript

Questions JavaScript Senior

25 questions avancees JavaScript/TypeScript pour les profils seniors. Patterns avances, performance, sécurité et architecture.

1. Expliquez le fonctionnement de l'event loop en JavaScript.

L'event loop est le mécanisme qui permet à JavaScript (single-threaded) de gérer l'asynchrone. Le moteur execute le code synchrone dans la call stack. Les opérations asynchrones (setTimeout, fetch, I/O) sont deleguees aux Web APIs du navigateur (ou libuv dans Node.js). Une fois terminees, leurs callbacks sont places dans la task queue (macrotasks). Les Promises et les MutationObserver utilisent la microtask queue, traitee prioritairement. Cycle : 1) Exécuter la call stack, 2) Vider la microtask queue, 3) Exécuter une macrotask, 4) Repeter. Les microtasks sont toujours traitées avant la prochaine macrotask. Comprendre cette priorité explique pourquoi Promise.resolve().then() s'execute avant setTimeout(fn, 0).

2. Comment fonctionne le système de prototypes en JavaScript ?

Chaque objet JavaScript a un prototype interne ([[Prototype]]). Quand on accède à une propriété, le moteur cherche d'abord sur l'objet, puis remonte la chaîne de prototypes jusqu'à Object.prototype (puis null). Les classes ES6 sont du sucre syntaxique sur les prototypes. Object.create(proto) cree un objet avec le prototype specifie. Object.getPrototypeOf(obj) retourne le prototype. Le prototype pattern : les méthodes partagees sont sur le prototype (une seule copie en mémoire), les propriétés d'instance sur l'objet. Attention : modifier un prototype affecte tous les objets qui en heritent. Les propriétés propres masquent les propriétés du prototype (shadowing). hasOwnProperty distingue les propriétés propres des heritees.

3. Expliquez les closures et leurs cas d'utilisation avances.

Une closure est une fonction qui capture les variables de son scope englobant, même après que ce scope a termine son exécution. Le mécanisme : la fonction garde une référence au lexical environment de sa création. Cas d'utilisation : encapsulation (simuler les variables privées avec un IIFE ou un module), factories (fonction retournant des fonctions configurées), currying (f(a)(b)(c) au lieu de f(a,b,c)), memoization (cache dans la closure), event handlers (capturer des variables dans les callbacks). Piège classique : la boucle for avec var (toutes les closures partagent la même variable). Solution : let (block-scoped) ou IIFE. Les closures gardent des références, pas des copies, ce qui peut causer des fuites mémoire si les objets références sont volumineux.

4. Qu'est-ce que les Proxies et Reflect en JavaScript ?

Le Proxy intercepte les opérations fondamentales sur un objet (lecture, écriture, appel de fonction, etc.) via des traps. Syntaxe : new Proxy(target, handler). Traps courantes : get (lecture de propriété), set (écriture), has (opérateur in), deleteProperty (delete), apply (appel de fonction), construct (new). Reflect fournit les méthodes correspondantes aux traps avec le comportement par défaut. Cas d'utilisation : validation (vérifier les types a l'écriture), observation/réactivité (Vue 3 utilise Proxy pour la réactivité), logging (tracer les accès), valeurs par défaut (retourner une valeur si la propriété n'existe pas), revocable proxies pour le contrôle d'accès temporaire.

5. Comment gérer la concurrence et le parallélisme en JavaScript ?

JavaScript est single-threaded mais gere la concurrence via l'event loop et les callbacks/promises. Web Workers : threads séparés pour les tâches CPU-intensives, communication par messages (postMessage), pas d'accès au DOM. SharedArrayBuffer + Atomics : mémoire partagee entre workers avec opérations atomiques pour la synchronisation. Promise.all : parallelise des opérations asynchrones indépendantes. Promise.allSettled : attend toutes les promises même si certaines rejettent. Promise.race : retourne la première promise resolue. AbortController : annuler des opérations asynchrones (fetch, event listeners). Structured concurrency : pattern ou les tâches enfants sont liées au cycle de vie du parent. En Node.js, les worker_threads pour le parallélisme CPU.

6. Expliquez les WeakMap, WeakSet et WeakRef.

WeakMap : map dont les clés sont des références faibles vers des objets. Si l'objet cle n'a plus d'autres références, il est garbage collected (et l'entrée disparait). Les clés ne sont pas itérables. Cas d'utilisation : metadata privée sur des objets sans empêcher leur GC, caching lie à la durée de vie d'un objet, DOM metadata (associer des données à des éléments sans fuite mémoire). WeakSet : ensemble d'objets avec des références faibles (marquer des objets comme "vus"). WeakRef : référence faible explicite vers un objet, deref() retourne l'objet ou undefined s'il a été GC. FinalizationRegistry : callback quand un objet est garbage collected. Ces structures sont essentielles pour éviter les fuites mémoire dans les applications longue durée.

7. Comment fonctionne le module system en JavaScript moderne ?

ES Modules (ESM) : standard officiel. import/export, statique (analysable au build pour tree-shaking), asynchrone, strict mode par défaut. CommonJS (CJS) : historique Node.js, require/module.exports, synchrone, dynamique. Dynamic import : import() retourne une Promise, utile pour le code splitting et le lazy loading. Import maps : mapping des specifiers aux URLs dans le navigateur (sans bundler). Tree-shaking : elimination du code mort, possible grace aux imports statiques ESM. Les bundlers (Webpack, Vite, esbuild) resolvent les modules et optimisent le bundle. Top-level await : await directement dans un module ESM (pas besoin de wrapper async). Le pattern barrel (index.js re-exportant tout) peut nuire au tree-shaking si mal utilise.

8. Quels sont les patterns de programmation fonctionnelle en JavaScript ?

Fonctions pures : même entrée donne toujours la même sortie, pas d'effets de bord. Immutabilité : ne pas modifier les données, créer de nouvelles copies (spread operator, Object.freeze, Immer). Higher-order functions : fonctions qui prennent ou retournent des fonctions (map, filter, reduce). Composition : combiner des fonctions simples en fonctions complexes (pipe/compose). Currying : transformer f(a,b) en f(a)(b) pour l'application partielle. Functors : conteneurs mappable (Array.map, Promise.then). Monades : chaîner des opérations avec gestion du contexte (Promise est monadique). En pratique : préférer la transformation de données aux mutations, utiliser les méthodes d'array fonctionnelles, éviter les boucles imperatives. Bibliothèques : Ramda, fp-ts pour le TypeScript.

9. Comment optimiser les performances JavaScript dans le navigateur ?

Critical rendering path : minimiser le JS bloquant le rendu, defer/async pour les scripts. Code splitting : charger le JS nécessaire à la page courante, lazy load le reste. Tree-shaking : eliminer le code mort au build. Web Workers : déplacer les calculs lourds hors du main thread. requestAnimationFrame : synchroniser les animations avec le rafraichissement écran. Debounce/throttle : limiter la fréquence d'exécution des handlers d'événements. Virtualisation : ne rendre que les éléments visibles dans les listes longues. Memory management : éviter les fuites (event listeners non supprimes, closures retenant des objets, timers oublies). Performance API : mesurer avec performance.mark/measure. Lighthouse et les Core Web Vitals (LCP, FID, CLS) pour le monitoring.

10. Expliquez les generators et les iterators en JavaScript.

Les iterators implementent le protocole d'itération : un objet avec une méthode next() retournant { value, done }. Le protocole iterable : un objet avec Symbol.iterator retournant un iterator. Les structures itérables : Array, String, Map, Set, arguments. Les generators (function*) simplifient la création d'iterators. yield suspend l'exécution et retourne une valeur. yield* delegue à un autre generator. Cas d'utilisation : génération de séquences infinies (Fibonacci), itération paresseuse (lazy évaluation), flux de contrôle asynchrone (avec yield et promises, precurseur d'async/await), pipelines de transformation de données. La boucle for...of et le spread operator consomment les itérables. Async generators (async function*) combinent generators et async pour les flux de données asynchrones (lecture de fichier ligne par ligne).

Besoin d'aide pour préparer vos entretiens ?

Decrivez votre profil pour des conseils de preparation personnalises.

Recevoir des conseils

Questions fréquentes

Quel framework JS maitriser en 2026 ?
React reste dominant, mais Next.js, Astro et Svelte gagnent du terrain. La polyvalence est un atout.

Pages liées

Chaque semaine, le meilleur de la tech française

Tendances, salaires, outils et opportunités — directement dans votre boîte mail.

Gratuit. Desabonnement en un clic. Pas de spam.