SiamCafe.net Blog
Technology

Web Components Interview Preparation

web components interview preparation
Web Components Interview Preparation | SiamCafe Blog
2025-11-10· อ. บอม — SiamCafe.net· 8,583 คำ

Web Components

Web Components เป็น Web Standard สร้าง Reusable UI Components ทำงานได้ทุก Browser ทุก Framework Custom Elements Shadow DOM HTML Templates ES Modules

เตรียมตัวสัมภาษณ์งาน ต้องเข้าใจ Core APIs Lifecycle Callbacks Best Practices และสามารถเขียน Code ได้จริง

Core Web Components APIs

// === Web Components — Core APIs ===

// 1. Custom Element — Basic
class MyCounter extends HTMLElement {
 constructor() {
 super();
 this._count = 0;
 this.attachShadow({ mode: 'open' });
 }

 // Lifecycle Callbacks
 connectedCallback() {
 // เรียกเมื่อ Element ถูกเพิ่มเข้า DOM
 this.render();
 console.log('MyCounter connected to DOM');
 }

 disconnectedCallback() {
 // เรียกเมื่อ Element ถูกลบออกจาก DOM
 console.log('MyCounter removed from DOM');
 }

 // Observed Attributes
 static get observedAttributes() {
 return ['initial-count', 'step'];
 }

 attributeChangedCallback(name, oldVal, newVal) {
 // เรียกเมื่อ Attribute เปลี่ยน
 if (name === 'initial-count') {
 this._count = parseInt(newVal) || 0;
 }
 this.render();
 }

 // Getters/Setters (Properties)
 get count() { return this._count; }
 set count(val) {
 this._count = val;
 this.render();
 this.dispatchEvent(new CustomEvent('count-changed', {
 detail: { count: this._count },
 bubbles: true,
 composed: true, // ผ่าน Shadow DOM boundary
 }));
 }

 increment() {
 const step = parseInt(this.getAttribute('step')) || 1;
 this.count = this._count + step;
 }

 decrement() {
 const step = parseInt(this.getAttribute('step')) || 1;
 this.count = this._count - step;
 }

 render() {
 this.shadowRoot.innerHTML = `
 
 
 
 
 `;
 this.shadowRoot.getElementById('inc')
 .addEventListener('click', () => this.increment());
 this.shadowRoot.getElementById('dec')
 .addEventListener('click', () => this.decrement());
 }
}

// Register
customElements.define('my-counter', MyCounter);

// 2. HTML Template + Slot
// 

class MyCard extends HTMLElement {
 constructor() {
 super();
 const shadow = this.attachShadow({ mode: 'open' });
 // const template = document.getElementById('card-template');
 // shadow.appendChild(template.content.cloneNode(true));

 shadow.innerHTML = `
 
 
`; } } customElements.define('my-card', MyCard); // Usage: // //

Title

//

Content goes here

// Footer //
console.log('Web Components registered:'); console.log(' — Counter with Shadow DOM'); console.log(' — Card with Slots');

Interview Questions

// interview_questions.js — Web Components Interview Q&A
const questions = [
 {
 q: "Web Components ประกอบด้วยอะไรบ้าง",
 a: "4 เทคโนโลยี: Custom Elements, Shadow DOM, HTML Templates, ES Modules",
 difficulty: "basic",
 },
 {
 q: "Lifecycle Callbacks มีอะไรบ้าง",
 a: `constructor() — สร้าง Element
connectedCallback() — เพิ่มเข้า DOM
disconnectedCallback() — ลบออกจาก DOM
attributeChangedCallback(name, old, new) — Attribute เปลี่ยน
adoptedCallback() — ย้ายไปอีก Document`,
 difficulty: "basic",
 },
 {
 q: "Shadow DOM open กับ closed ต่างกันอย่างไร",
 a: `open: เข้าถึง shadowRoot จากภายนอกได้ (element.shadowRoot)
closed: เข้าถึง shadowRoot จากภายนอกไม่ได้ (return null)
ส่วนใหญ่ใช้ open เพราะยืดหยุ่นกว่า`,
 difficulty: "intermediate",
 },
 {
 q: ":host และ :host() ใช้อย่างไร",
 a: `:host — Style ตัว Host Element เอง
:host(.active) — Style เมื่อ Host มี class .active
:host-context(.dark) — Style เมื่ออยู่ใน Context .dark
::slotted(p) — Style slotted elements`,
 difficulty: "intermediate",
 },
 {
 q: "Custom Event ส่งผ่าน Shadow DOM ได้อย่างไร",
 a: `ใช้ composed: true ใน CustomEvent options
new CustomEvent('my-event', {
 detail: { data: 'value' },
 bubbles: true,
 composed: true // ผ่าน Shadow DOM boundary
})`,
 difficulty: "advanced",
 },
 {
 q: "Web Components กับ Framework (React/Vue) ใช้ร่วมกันได้หรือไม่",
 a: `ได้ — Web Components เป็น Standard ใช้ใน React, Vue, Angular ได้
React: ใช้ ref สำหรับ Properties, addEventListener สำหรับ Events
Vue: ใช้ v-bind สำหรับ Properties, @ สำหรับ Events
Angular: ใช้ CUSTOM_ELEMENTS_SCHEMA`,
 difficulty: "advanced",
 },
 {
 q: "Form-associated Custom Elements คืออะไร",
 a: `Custom Elements ที่ทำงานร่วมกับ HTML Form ได้
ใช้ static formAssociated = true
ใช้ ElementInternals API (this.attachInternals())
สามารถ setFormValue, reportValidity ได้`,
 difficulty: "advanced",
 },
];

console.log("Web Components Interview Questions:");
console.log("=" .repeat(55));

for (const { q, a, difficulty } of questions) {
 const icon = difficulty === 'basic' ? 'B' :
 difficulty === 'intermediate' ? 'I' : 'A';
 console.log(`\n [] Q: `);
 console.log(` A: `);
}

// Performance Tips
const tips = {
 "Lazy Rendering": "render ใน connectedCallback ไม่ใช่ constructor",
 "Event Delegation": "ใช้ Event Delegation แทน addEventListener ทุก Element",
 "Attribute vs Property": "Attribute = string เท่านั้น, Property = any type",
 "observedAttributes": "ต้อง return array ใน static get observedAttributes",
 "Memory Leaks": "cleanup ใน disconnectedCallback ลบ Event Listeners",
};

console.log("\n\nPerformance Tips:");
for (const [tip, desc] of Object.entries(tips)) {
 console.log(` : `);
}

Advanced Patterns

// advanced_patterns.js — Advanced Web Component Patterns

// 1. Mixin Pattern
const EventEmitterMixin = (Base) => class extends Base {
 _listeners = new Map();

 on(event, callback) {
 if (!this._listeners.has(event)) {
 this._listeners.set(event, []);
 }
 this._listeners.get(event).push(callback);
 }

 emit(event, data) {
 const callbacks = this._listeners.get(event) || [];
 callbacks.forEach(cb => cb(data));
 this.dispatchEvent(new CustomEvent(event, {
 detail: data, bubbles: true, composed: true,
 }));
 }
};

// 2. Reactive Properties Pattern
class ReactiveElement extends HTMLElement {
 static get properties() { return {}; }

 constructor() {
 super();
 this.attachShadow({ mode: 'open' });
 this._props = {};

 // Create reactive properties
 const props = this.constructor.properties;
 for (const [name, config] of Object.entries(props)) {
 const defaultVal = config.default !== undefined ? config.default : null;
 this._props[name] = defaultVal;

 Object.defineProperty(this, name, {
 get: () => this._props[name],
 set: (val) => {
 const old = this._props[name];
 this._props[name] = val;
 if (old !== val) {
 this.requestUpdate();
 }
 },
 });
 }
 }

 requestUpdate() {
 if (!this._updateQueued) {
 this._updateQueued = true;
 Promise.resolve().then(() => {
 this._updateQueued = false;
 this.render();
 });
 }
 }

 connectedCallback() { this.render(); }
 render() { /* Override in subclass */ }
}

// 3. Usage
class TodoList extends ReactiveElement {
 static get properties() {
 return {
 items: { default: [] },
 filter: { default: 'all' },
 };
 }

 render() {
 const filtered = this.filter === 'all' ? this.items :
 this.items.filter(i => this.filter === 'done' ? i.done : !i.done);

 this.shadowRoot.innerHTML = `
 
 
" data-filter=""> `).join('')}
    " data-index=""> `).join('')}

items

`; // Event Delegation this.shadowRoot.addEventListener('click', (e) => { if (e.target.dataset.filter) { this.filter = e.target.dataset.filter; } if (e.target.dataset.index !== undefined) { const idx = parseInt(e.target.dataset.index); this.items = this.items.map((item, i) => i === idx ? { ...item, done: !item.done } : item ); } }); } } customElements.define('todo-list', TodoList); // Testing Web Components // const el = document.createElement('todo-list'); // el.items = [ // { text: 'Learn Web Components', done: true }, // { text: 'Build Custom Elements', done: false }, // { text: 'Master Shadow DOM', done: false }, // ]; // document.body.appendChild(el); console.log("Advanced Patterns:"); console.log(" 1. Mixin Pattern — EventEmitterMixin"); console.log(" 2. Reactive Properties — Auto re-render on change"); console.log(" 3. Event Delegation — Single listener on shadowRoot"); console.log(" 4. Batched Updates — requestUpdate with microtask");

เคล็ดลับสัมภาษณ์

Web Components คืออะไร

Web Standard 4 เทคโนโลยี Custom Elements Shadow DOM HTML Templates ES Modules สร้าง Reusable UI Components ทุก Browser ทุก Framework

Shadow DOM คืออะไร

สร้าง DOM Tree แยก Main DOM CSS JavaScript ภายในไม่กระทบภายนอก ภายนอกไม่กระทบภายใน ป้องกัน Style Leaking attachShadow mode open

Custom Elements มีกี่แบบ

2 แบบ Autonomous สร้างจาก HTMLElement ใหม่ทั้งหมด Customized Built-in สร้างจาก Element มีอยู่ extends HTMLButtonElement ใช้ is attribute

Web Components เทียบกับ React Components อย่างไร

WC Web Standard ทุก Framework ไม่พึ่ง Library ขนาดเล็ก ไม่มี State Management Virtual DOM React JSX State Hooks Virtual DOM Ecosystem ใหญ่ ต้องพึ่ง Library ใช้ร่วมกันได้

สรุป

Web Components เป็น Web Standard Custom Elements Shadow DOM HTML Templates เตรียมสัมภาษณ์ต้องเข้าใจ Lifecycle Callbacks Shadow DOM Encapsulation Slots Events composed Advanced Patterns Mixin Reactive Properties ใช้ร่วมกับ React Vue Angular ได้

📖 บทความที่เกี่ยวข้อง

Java Micronaut Interview Preparationอ่านบทความ → Ansible Vault Interview Preparationอ่านบทความ → Azure DevOps Pipeline Interview Preparationอ่านบทความ → SSE Security Interview Preparationอ่านบทความ → Kustomize Overlay Interview Preparationอ่านบทความ →

📚 ดูบทความทั้งหมด →