InterviewHubPRO
Section Overview
Q512

Question 512 of 521

Part 8: Modern JavaScript APIs, WeakRef, Proxy & Performance (464 - 521)

98%
JavaScript Internals (521 Qs)•Part 8: Modern JavaScript APIs, WeakRef, Proxy & Performance (464 - 521)

How does the Mutation Observer API work?

The MutationObserver API provides a way to watch for changes to the DOM tree, replacing the deprecated mutation events.

Basic usage:

javascript
 const observer = new MutationObserver((mutations) => {
   mutations.forEach(mutation => {
     console.log('Type:', mutation.type);
     console.log('Target:', mutation.target);
   });
 });

 const config = {
   attributes: true,
   childList: true,
   subtree: true
 };

 const targetNode = document.getElementById('observed');
 observer.observe(targetNode, config);

 // Later: stop observing
 observer.disconnect();

Observing attribute changes:

javascript
 const observer = new MutationObserver((mutations) => {
   mutations.forEach(mutation => {
     if (mutation.type === 'attributes') {
       const oldValue = mutation.oldValue;
       const newValue = mutation.target.getAttribute(mutation.attributeName);
       console.log(`${mutation.attributeName}: ${oldValue} → ${newValue}`);
     }
   });
 });

 observer.observe(element, {
   attributes: true,
   attributeOldValue: true,
   attributeFilter: ['class', 'data-status']
 });

Observing child nodes:

javascript
 const observer = new MutationObserver((mutations) => {
   mutations.forEach(mutation => {
     mutation.addedNodes.forEach(node => {
       console.log('Added:', node);
     });
     mutation.removedNodes.forEach(node => {
       console.log('Removed:', node);
     });
   });
 });

 observer.observe(container, {
   childList: true,
   subtree: true
 });

Practical example - lazy loading images when added to DOM:

javascript
 const imageObserver = new MutationObserver((mutations) => {
   mutations.forEach(mutation => {
     mutation.addedNodes.forEach(node => {
       if (node.tagName === 'IMG' && node.dataset.src) {
         loadImage(node);
       }
       // Check descendants
       if (node.querySelectorAll) {
         node.querySelectorAll('img[data-src]').forEach(loadImage);
       }
     });
   });
 });

 function loadImage(img) {
   img.src = img.dataset.src;
   delete img.dataset.src;
 }

 imageObserver.observe(document.body, {
   childList: true,
   subtree: true
 });

Observing text content changes:

javascript
 const observer = new MutationObserver((mutations) => {
   mutations.forEach(mutation => {
     if (mutation.type === 'characterData') {
       console.log('Text changed:', mutation.target.textContent);
     }
   });
 });

 observer.observe(textNode, {
   characterData: true,
   characterDataOldValue: true
 });

Configuration options:

javascript
 const config = {
   attributes: true,           // Watch attribute changes
   attributeOldValue: true,    // Record old attribute values
   attributeFilter: ['class'], // Only watch specific attributes
   childList: true,            // Watch child nodes
   subtree: true,              // Watch all descendants
   characterData: true,        // Watch text content
   characterDataOldValue: true // Record old text content
 };