Préparation d'entretien 100% Gratuit angularforall.com

Entretien Vanilla JS Senior — Performance et Web APIs

Vanilla-Js Javascript-Natif Quiz-Vanilla-Js-Senior Web-Workers Proxy Intersection-Observer Mutationobserver Requestanimationframe Debounce Throttle Generators Weakmap Questions-Entretien-Vanilla-Js-Senior Qcm-Vanilla-Js-Avance
Sénior 🔀 Mixte 20 questions ⏱ 15 min
📝

Entretien Vanilla JS Senior — Performance et Web APIs

20 questions Vanilla JS niveau senior : Web Workers, Proxy, MutationObserver, IntersectionObserver, requestAnimationFrame, generators, WeakMap, debounce/throttle et patterns avancés. Pour réussir un entretien Senior JS natif.

20 questions ⏱ ~15 min Niveau Sénior

Partager

Banque de révision : les 30 questions corrigées

Voici l'intégralité des 30 questions de « Entretien Vanilla JS Senior — Performance et Web APIs », chacune avec sa bonne réponse et son explication. Le quiz interactif ci-dessus en tire une sélection aléatoire à chaque tentative — utilisez cette liste complète pour réviser.

  • Un service de deploiement web
  • Un script qui s'execute dans un thread separe en arriere-plan (bonne réponse)
  • Un type de cookie session
  • Un alias pour les Service Workers
Explication : Web Workers s'executent dans un thread separe, sans acces au DOM. Communication via postMessage(). Utile pour les calculs lourds (compression, crypto, parsers) qui bloqueraient sinon le thread principal.
Web Worker = thread separe | postMessage = communication avec le main thread

  • Cree une animation CSS via JavaScript
  • Planifie l'execution d'une fonction avant le prochain repaint du navigateur (bonne réponse)
  • Joue une animation video frame par frame
  • Met une animation CSS en pause
Explication : requestAnimationFrame(fn) appelle fn avant que le navigateur ne redessine l'ecran (~60fps). Contrairement a setInterval, il s'adapte au framerate, economise la batterie si l'onglet est inactif et evite les sautes.
rAF = synchronise avec le repaint | ideal pour les animations JS fluides

  • Un cache HTTP au niveau du navigateur
  • Un objet qui intercepte et redefinit les operations sur un autre objet (bonne réponse)
  • Un pattern de routage pour les SPA
  • Un generateur de nombres aleatoires securise
Explication : Proxy(target, handler) permet d'intercepter les operations : get, set, has, deleteProperty, apply, construct, etc. Utile pour la validation de donnees, la journalisation, les objets reactifs (Vue 3 l'utilise en interne).
Proxy = intercepteur d'operations sur objet (get/set/delete...)

  • Modifie le DOM automatiquement selon des regles
  • Observe les changements dans le DOM (ajout/suppression de noeuds, attributs, texte) (bonne réponse)
  • Surveille les mutations de variables JavaScript
  • Detecte les erreurs JavaScript non capturees
Explication : MutationObserver observe de facon asynchrone les changements DOM. On configure ce qu'on observe : childList (enfants), attributes, characterData, subtree. Remplace les anciens Mutation Events depreciees.
MutationObserver = React au changement DOM | observe({childList: true, subtree: true})

  • Un operateur mathematique special
  • Un identifiant unique et immuable utilise comme cle de propriete (bonne réponse)
  • Un type de collection indexee
  • Une fonction native du DOM
Explication : Symbol() cree une valeur primitive unique. Symbol("desc") !== Symbol("desc"). Utilise pour des cles de proprietes privees ou pour implenter des protocoles comme [Symbol.iterator]. Jamais enumere par for...in.
Symbol() = toujours unique | [Symbol.iterator] = protocole iterable

  • Un tableau des valeurs yielded
  • Un iterateur avec la methode next() retournant {value, done} (bonne réponse)
  • Une promesse resolue avec toutes les valeurs
  • Un objet ordinaire avec les resultats
Explication : function* retourne un generateur (iterateur). Chaque appel a next() execute jusqu'au prochain yield. Le generateur retourne {value: yieldedValue, done: false} jusqu'a la fin, puis {value: undefined, done: true}.
function* + yield = generateur | next() = {value, done}

  • WeakMap est plus rapide que Map pour les grands ensembles
  • Les cles de WeakMap sont des references faibles (peuvent etre collectees par le GC) (bonne réponse)
  • WeakMap accepte des cles primitives contrairement a Map
  • WeakMap est iterable, Map ne l'est pas
Explication : WeakMap accepte uniquement des objets comme cles. Ces references sont faibles : si l'objet n'a plus d'autres references, il peut etre garbage collecte. WeakMap n'est pas enumerable ni iterable.
WeakMap = cles objets uniquement, references faibles, pas iterable

  • document.registerComponent("my-el", MyClass)
  • customElements.define("my-el", MyClass) (bonne réponse)
  • new WebComponent("my-el", MyClass)
  • CustomElement.register("my-el", MyClass)
Explication : customElements.define(name, constructor) enregistre un element personnalise. Le nom doit contenir un tiret (my-component). La classe etend HTMLElement et peut implementer connectedCallback, disconnectedCallback, attributeChangedCallback.
customElements.define() + classe extends HTMLElement = Web Component

  • Exposer toutes les proprietes d'un module via export *
  • Encapsuler un module et n'exposer que les methodes et proprietes choisies via un objet retourne (bonne réponse)
  • Importer des modules ES6 de facon dynamique
  • Un pattern pour tester des modules en isolation
Explication : Le Revealing Module Pattern utilise une IIFE qui retourne un objet exposant uniquement les API publiques. Les variables internes sont privees par closure. Precede les modules ES6 natifs.
Revealing Module = IIFE + closure + objet retourne avec API publique

  • Cree une copie immutable de l'objet
  • Rend l'objet immutable : pas d'ajout, modification ou suppression de proprietes (bonne réponse)
  • Gele temporairement l'objet pendant 1 seconde
  • Serialise l'objet en JSON fige
Explication : Object.freeze() rend un objet immutable en surface (shallow). Les proprietes ne peuvent plus etre modifiees, ajoutees ou supprimees. En mode strict, toute tentative lance une TypeError. Pour une immutabilite profonde, il faut recursivement freeze.
freeze = immutable en surface | deep freeze = appel recursif

  • Supprimer les doublons dans un tableau de facon efficace
  • Retarder l'execution jusqu'a ce que la fonction ne soit plus appelee pendant X ms (bonne réponse)
  • Limiter les appels a exactement N fois par seconde
  • Annuler un setTimeout en cours
Explication : Le debounce attend que les appels s'arretent avant d'executer. Ex: debounce(search, 300) attend 300ms d'inactivite avant de lancer la recherche. Ideal pour la saisie utilisateur (input, resize).
Debounce = attend la fin des appels | Throttle = limite la frequence

  • Aucune difference : ils font la meme chose avec des noms differents
  • Debounce attend la fin des appels, throttle garantit une execution maximum par intervalle (bonne réponse)
  • Throttle attend la fin des appels, debounce limite la frequence
  • Debounce est plus rapide que throttle en toutes circonstances
Explication : Debounce : si vous tapez continument, la fonction attend que vous arrietiez. Throttle : la fonction s'execute au maximum une fois par intervalle meme si vous continuez. Throttle = scroll, debounce = recherche.
Debounce = fin d'activite | Throttle = cadence reguliere maximale

  • Retourne le pourcentage de charge CPU
  • Retourne un timestamp haute resolution en millisecondes depuis le chargement de la page (bonne réponse)
  • Lance le profilage automatique du code
  • Mesure la performance reseau des requetes
Explication : performance.now() retourne un DOMHighResTimeStamp avec une precision sous-milliseconde. Contrairement a Date.now(), il n'est pas affecte par les ajustements d'horloge systeme. Ideal pour mesurer des durees precises.
performance.now() = haute precision | Date.now() = timestamp Unix en ms

  • Clone la structure du DOM en profondeur
  • Cree une copie PROFONDE d'un objet (deep clone natif) (bonne réponse)
  • Clone un tableau de facon superficielle
  • Duplique une instance de classe avec ses methodes
Explication : structuredClone() cree une copie profonde via l'algorithme de clonage structure. Supporte : objets, tableaux, Map, Set, Date, RegExp, ArrayBuffer, etc. Ne supporte pas les fonctions ni les noeuds DOM.
structuredClone() = deep clone natif (plus simple que JSON.parse/stringify)

  • Une fonction async qui genere des promesses en boucle
  • Une fonction generatrice asynchrone retournant un async iterateur utilisant for await...of (bonne réponse)
  • Un generateur qui s'execute en arriere-plan dans un Worker
  • Un generator imbrique dans une promesse ordinaire
Explication : async function* combine generateur et async. Chaque yield peut etre une promesse. On itere avec for await...of. Utile pour consommer des flux de donnees paginates ou des streams API.
async function* + yield + for await...of = flux de donnees asynchrones

  • new IntersectionObserver(callback).observe(img) (bonne réponse)
  • document.onScroll(() => checkImages())
  • img.loading = "lazy"
  • window.observe(img)
Explication : On cree un IntersectionObserver, on passe une callback qui recoit les entries, on filtre isIntersecting, on charge l'image (data-src -> src), puis on appelle unobserve(). Plus performant que les evenements scroll.
new IntersectionObserver(cb).observe(el) | isIntersecting pour declencher

  • Immediately Invoked Function Expression : s'execute immediatement apres sa definition (bonne réponse)
  • Infinite Iterative Function Expression pour les boucles sans fin
  • Internal Interface Function Expression pour les modules
  • Indexed Immutable Function Expression pour les tableaux
Explication : L'IIFE (() => { ... })() cree une portee isolee. Les variables internes ne polluent pas le scope global. Tres utilise avant les modules ES6 pour l'encapsulation. Encore utile pour initialiser du code sans polluer.
IIFE = (() => { code })() : portee isolee, execution immediate

  • Applique une transformation CSS a un element
  • Appelle une fonction avec un contexte et des arguments donnes (similaire a Function.prototype.apply) (bonne réponse)
  • Reflecte les proprietes d'un objet dans un autre
  • Applique un handler Proxy a un objet existant
Explication : Reflect.apply(fn, ctx, args) est equivalent a fn.apply(ctx, args) mais fait partie de l'API Reflect qui correspond 1:1 aux traps Proxy. Utile dans les handlers Proxy pour appeler le comportement par defaut.
Reflect.apply() = Function.apply() mais via l'API Reflect standard

  • Un DOM cache uniquement visible dans les DevTools
  • Un sous-arbre DOM encapsule et isole du DOM principal, utilise dans les Web Components (bonne réponse)
  • Un DOM virtuel pour les animations hautes performances
  • Le DOM en mode d'affichage dark theme
Explication : Le Shadow DOM cree un arbre DOM encapsule : les styles CSS n'en sortent pas et les styles externes n'y entrent pas. On l'attache avec element.attachShadow({mode: "open"}). Base des Web Components natifs.
Shadow DOM = encapsulation CSS + DOM | base des Web Components

  • Retourne les proprietes heritees du prototype
  • Retourne le descripteur d'une propriete : value, writable, enumerable, configurable (bonne réponse)
  • Supprime et retourne une propriete de l'objet
  • Copie les descripteurs vers un autre objet
Explication : Retourne un objet avec : value (valeur), writable (modifiable), enumerable (visible dans for...in), configurable (peut etre supprimee/modifiee). Les proprietes non-writable sont lues seules. Utile pour le metaprogramming.
Descripteur = value + writable + enumerable + configurable

  • Utiliser des closures pour capturer les references
  • Stocker la reference de la fonction et appeler removeEventListener au bon moment
  • Utiliser des WeakRef pour les handlers d'evenements
  • Les deux B et C sont des bonnes pratiques (bonne réponse)
Explication : removeEventListener necessite la meme reference de fonction qu'addEventListener. Les fonctions anonymes ne peuvent pas etre supprimees. WeakRef permet aussi des references faibles vers des objets handler pour eviter les retentions.
Fuite memoire = listener non supprime | stocker la reference + removeEventListener

  • Utiliser uniquement MutationObserver pour les changements DOM
  • Implenter subscribe/publish avec des tableaux de callbacks pour un bus d'evenements (bonne réponse)
  • Observer les changements de l'URL avec history API
  • Combiner MutationObserver et IntersectionObserver
Explication : Le pattern Observer (pub/sub) maintient une liste de subscribers. emit() appelle toutes les callbacks. subscribe() ajoute une callback, unsubscribe() la retire. Base de nombreux systemes de gestion d'etat.
Observer = subscribe/emit/unsubscribe | base des stores reactifs

  • File une tache dans la file des macrotaches (comme setTimeout)
  • File une tache dans la file des microtaches, executee avant le prochain repaint (bonne réponse)
  • Cree un nouveau thread de microtaches
  • Planifie une tache comme setTimeout(fn, 0) mais avec priorite
Explication : Les microtaches (Promise.then, queueMicrotask, MutationObserver) s'executent apres le code courant mais avant les macrotaches (setTimeout, setInterval). queueMicrotask() est plus explicite et semantique qu'une promesse resolue.
Ordre : code sync -> microtaches -> macrotaches | queueMicrotask = priorite haute

  • Implenter la methode [Symbol.iterator]() retournant un objet avec next() -> {value, done} (bonne réponse)
  • Utiliser Array.from() avec un objet quelconque
  • Etendre la classe Iterator avec des methodes personnalisees
  • Utiliser function* avec des valeurs fixes
Explication : Un objet est iterable s'il a une methode [Symbol.iterator]() retournant un iterateur. L'iterateur a une methode next() qui retourne {value: any, done: boolean}. Permet d'utiliser for...of, spread, destructuration.
[Symbol.iterator]() + next() = protocole iterable personnalise

  • Stocker les resultats de fonctions couteuses dans un cache pour les reutiliser (bonne réponse)
  • Optimiser la memoire du navigateur en compressant les variables
  • Memoriser l'etat du DOM pour le restaurer plus tard
  • Sauvegarder les resultats de calcul dans localStorage
Explication : La memoization cache les resultats en fonction des arguments. Ex: memo.get(arg) || (result = fn(arg), memo.set(arg, result), result). Ideal pour les fonctions pures couteuses (fibonacci, calculs, parsers).
Memoization = cache des resultats par arguments (Map ou WeakMap)

  • Supprime les valeurs nulles et undefined du tableau
  • Aplatit un tableau imbrique en tableau de profondeur inferieure selon depth (bonne réponse)
  • Trie le tableau par ordre croissant
  • Supprime les doublons en aplatissant les repetitions
Explication : [1,[2,[3]]].flat() = [1,2,[3]]. flat(Infinity) aplatit entierement. flatMap(fn) combine map() puis flat(1). Utile pour normaliser des donnees arborescentes ou les resultats de plusieurs fetch.
flat() = aplati 1 niveau | flat(Infinity) = aplati tout | flatMap = map + flat

  • Un template string avec des variables simples
  • Une fonction qui intercepte et transforme un template literal en controlant l'interpolation (bonne réponse)
  • Un composant web base sur des templates HTML
  • Un tag HTML genere dynamiquement par template
Explication : tag`Hello ${name}` appelle tag(strings, ...values). La fonction tag recoit les parties statiques (strings[]) et les valeurs interpolees. Utilise par styled-components, GraphQL (gql), sql, html templates securises.
Tagged template = fonction devant le backtick | intercepte l'interpolation

  • Appeler new Singleton() et verifier le compteur
  • Utiliser une closure ou un module ES6 pour garantir une seule instance (bonne réponse)
  • Utiliser Object.create(null) avec une propriete instance
  • Utiliser class static getInstance() uniquement
Explication : Avec les modules ES6, le singleton est naturel : la valeur exportee est mise en cache. Avec une closure : let instance; function getInstance(){ return instance || (instance = new MyClass()); }. static getInstance() est aussi valide.
Singleton = une instance unique | module ES6 = singleton naturel

  • Combine filter() et map() en une seule operation
  • Applique map() puis flat(1) : transforme et aplatit d'un niveau (bonne réponse)
  • Aplatit d'abord puis applique map() sur le resultat
  • Supprime les valeurs undefined apres le map
Explication : flatMap(fn) = map(fn).flat(1). Ex: ["hello world"].flatMap(s => s.split(" ")) = ["hello", "world"]. Plus performant que les deux appels separes. Utile pour transformer des tableaux en aplatissant les resultats.
flatMap = map + flat niveau 1 | ["a b"].flatMap(s => s.split(" ")) = ["a","b"]

  • Utiliser Array.prototype.reduce pour chainer les fonctions de droite a gauche (bonne réponse)
  • Utiliser Promise.all pour executer toutes les fonctions en parallele
  • Utiliser Object.assign pour fusionner les resultats des fonctions
  • Utiliser for...of pour appeler chaque fonction sequentiellement
Explication : compose(f, g, h)(x) = f(g(h(x))). Implementation : const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x). pipe() va dans l'autre sens : fns.reduce(). Base de la programmation fonctionnelle.
compose = reduceRight | pipe = reduce | f(g(h(x))) = composition de droite a gauche